Root/target/linux/lantiq/files/arch/mips/lantiq/falcon/sysctrl.c

1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com>
7 * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
8 */
9
10#include <linux/ioport.h>
11#include <linux/export.h>
12#include <linux/clkdev.h>
13#include <asm/delay.h>
14
15#include <lantiq_soc.h>
16
17#include "devices.h"
18#include "../clk.h"
19
20/* infrastructure control register */
21#define SYS1_INFRAC 0x00bc
22/* Configuration fuses for drivers and pll */
23#define STATUS_CONFIG 0x0040
24
25/* GPE frequency selection */
26#define GPPC_OFFSET 24
27#define GPEFREQ_MASK 0x00000C0
28#define GPEFREQ_OFFSET 10
29/* Clock status register */
30#define LTQ_SYSCTL_CLKS 0x0000
31/* Clock enable register */
32#define LTQ_SYSCTL_CLKEN 0x0004
33/* Clock clear register */
34#define LTQ_SYSCTL_CLKCLR 0x0008
35/* Activation Status Register */
36#define LTQ_SYSCTL_ACTS 0x0020
37/* Activation Register */
38#define LTQ_SYSCTL_ACT 0x0024
39/* Deactivation Register */
40#define LTQ_SYSCTL_DEACT 0x0028
41/* reboot Register */
42#define LTQ_SYSCTL_RBT 0x002c
43/* CPU0 Clock Control Register */
44#define LTQ_SYS1_CPU0CC 0x0040
45/* clock divider bit */
46#define LTQ_CPU0CC_CPUDIV 0x0001
47
48static struct resource ltq_sysctl_res[] = {
49    MEM_RES("sys1", LTQ_SYS1_BASE_ADDR, LTQ_SYS1_SIZE),
50    MEM_RES("syseth", LTQ_SYS_ETH_BASE_ADDR, LTQ_SYS_ETH_SIZE),
51    MEM_RES("sysgpe", LTQ_SYS_GPE_BASE_ADDR, LTQ_SYS_GPE_SIZE),
52};
53
54static struct resource ltq_status_res =
55    MEM_RES("status", LTQ_STATUS_BASE_ADDR, LTQ_STATUS_SIZE);
56static struct resource ltq_ebu_res =
57    MEM_RES("ebu", LTQ_EBU_BASE_ADDR, LTQ_EBU_SIZE);
58
59static void __iomem *ltq_sysctl[3];
60static void __iomem *ltq_status_membase;
61void __iomem *ltq_sys1_membase;
62void __iomem *ltq_ebu_membase;
63
64#define ltq_reg_w32(m, x, y) ltq_w32((x), ltq_sysctl[m] + (y))
65#define ltq_reg_r32(m, x) ltq_r32(ltq_sysctl[m] + (x))
66#define ltq_reg_w32_mask(m, clear, set, reg) \
67        ltq_reg_w32(m, (ltq_reg_r32(m, reg) & ~(clear)) | (set), reg)
68
69#define ltq_status_w32(x, y) ltq_w32((x), ltq_status_membase + (y))
70#define ltq_status_r32(x) ltq_r32(ltq_status_membase + (x))
71
72static inline void
73ltq_sysctl_wait(struct clk *clk,
74        unsigned int test, unsigned int reg)
75{
76    int err = 1000000;
77
78    do {} while (--err && ((ltq_reg_r32(clk->module, reg)
79                    & clk->bits) != test));
80    if (!err)
81        pr_err("module de/activation failed %d %08X %08X %08X\n",
82                clk->module, clk->bits, test,
83                ltq_reg_r32(clk->module, reg) & clk->bits);
84}
85
86static int
87ltq_sysctl_activate(struct clk *clk)
88{
89    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN);
90    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_ACT);
91    ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS);
92    return 0;
93}
94
95static void
96ltq_sysctl_deactivate(struct clk *clk)
97{
98    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR);
99    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_DEACT);
100    ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_ACTS);
101}
102
103static int
104ltq_sysctl_clken(struct clk *clk)
105{
106    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKEN);
107    ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_CLKS);
108    return 0;
109}
110
111static void
112ltq_sysctl_clkdis(struct clk *clk)
113{
114    ltq_reg_w32(clk->module, clk->bits, LTQ_SYSCTL_CLKCLR);
115    ltq_sysctl_wait(clk, 0, LTQ_SYSCTL_CLKS);
116}
117
118static void
119ltq_sysctl_reboot(struct clk *clk)
120{
121    unsigned int act;
122    unsigned int bits;
123
124    act = ltq_reg_r32(clk->module, LTQ_SYSCTL_ACT);
125    bits = ~act & clk->bits;
126    if (bits != 0) {
127        ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_CLKEN);
128        ltq_reg_w32(clk->module, bits, LTQ_SYSCTL_ACT);
129        ltq_sysctl_wait(clk, bits, LTQ_SYSCTL_ACTS);
130    }
131    ltq_reg_w32(clk->module, act & clk->bits, LTQ_SYSCTL_RBT);
132    ltq_sysctl_wait(clk, clk->bits, LTQ_SYSCTL_ACTS);
133}
134
135/* enable the ONU core */
136static void
137ltq_gpe_enable(void)
138{
139    unsigned int freq;
140    unsigned int status;
141
142    /* if if the clock is already enabled */
143    status = ltq_reg_r32(SYSCTL_SYS1, SYS1_INFRAC);
144    if (status & (1 << (GPPC_OFFSET + 1)))
145        return;
146
147    if (ltq_status_r32(STATUS_CONFIG) == 0)
148        freq = 1; /* use 625MHz on unfused chip */
149    else
150        freq = (ltq_status_r32(STATUS_CONFIG) &
151            GPEFREQ_MASK) >>
152            GPEFREQ_OFFSET;
153
154    /* apply new frequency */
155    ltq_reg_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1),
156        freq << (GPPC_OFFSET + 2) , SYS1_INFRAC);
157    udelay(1);
158
159    /* enable new frequency */
160    ltq_reg_w32_mask(SYSCTL_SYS1, 0, 1 << (GPPC_OFFSET + 1), SYS1_INFRAC);
161    udelay(1);
162}
163
164static inline void
165clkdev_add_sys(const char *dev, unsigned int module,
166                unsigned int bits)
167{
168    struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
169
170    clk->cl.dev_id = dev;
171    clk->cl.con_id = NULL;
172    clk->cl.clk = clk;
173    clk->module = module;
174    clk->bits = bits;
175    clk->activate = ltq_sysctl_activate;
176    clk->deactivate = ltq_sysctl_deactivate;
177    clk->enable = ltq_sysctl_clken;
178    clk->disable = ltq_sysctl_clkdis;
179    clk->reboot = ltq_sysctl_reboot;
180    clkdev_add(&clk->cl);
181}
182
183void __init
184ltq_soc_init(void)
185{
186    int i;
187
188    for (i = 0; i < 3; i++)
189        ltq_sysctl[i] = ltq_remap_resource(&ltq_sysctl_res[i]);
190
191    ltq_sys1_membase = ltq_sysctl[0];
192    ltq_status_membase = ltq_remap_resource(&ltq_status_res);
193    ltq_ebu_membase = ltq_remap_resource(&ltq_ebu_res);
194
195    ltq_gpe_enable();
196
197    /* get our 3 static rates for cpu, fpi and io clocks */
198    if (ltq_sys1_r32(LTQ_SYS1_CPU0CC) & LTQ_CPU0CC_CPUDIV)
199        clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M);
200    else
201        clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M);
202
203    /* add our clock domains */
204    clkdev_add_sys("falcon_gpio.0", SYSCTL_SYSETH, ACTS_PADCTRL0 | ACTS_P0);
205    clkdev_add_sys("falcon_gpio.1", SYSCTL_SYS1, ACTS_PADCTRL1 | ACTS_P1);
206    clkdev_add_sys("falcon_gpio.2", SYSCTL_SYSETH, ACTS_PADCTRL2 | ACTS_P2);
207    clkdev_add_sys("falcon_gpio.3", SYSCTL_SYS1, ACTS_PADCTRL3 | ACTS_P3);
208    clkdev_add_sys("falcon_gpio.4", SYSCTL_SYS1, ACTS_PADCTRL4 | ACTS_P4);
209    clkdev_add_sys("ltq_asc.1", SYSCTL_SYS1, ACTS_ASC1_ACT);
210    clkdev_add_sys("i2c-falcon.0", SYSCTL_SYS1, ACTS_I2C_ACT);
211}
212

Archive Download this file



interactive