diff options
Diffstat (limited to 'arch/mips/alchemy')
-rw-r--r-- | arch/mips/alchemy/board-mtx1.c | 4 | ||||
-rw-r--r-- | arch/mips/alchemy/board-xxs1500.c | 4 | ||||
-rw-r--r-- | arch/mips/alchemy/common/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/alchemy/common/clock.c | 1094 | ||||
-rw-r--r-- | arch/mips/alchemy/common/clocks.c | 105 | ||||
-rw-r--r-- | arch/mips/alchemy/common/dbdma.c | 22 | ||||
-rw-r--r-- | arch/mips/alchemy/common/dma.c | 15 | ||||
-rw-r--r-- | arch/mips/alchemy/common/irq.c | 5 | ||||
-rw-r--r-- | arch/mips/alchemy/common/platform.c | 15 | ||||
-rw-r--r-- | arch/mips/alchemy/common/power.c | 74 | ||||
-rw-r--r-- | arch/mips/alchemy/common/setup.c | 15 | ||||
-rw-r--r-- | arch/mips/alchemy/common/time.c | 23 | ||||
-rw-r--r-- | arch/mips/alchemy/common/usb.c | 47 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1000.c | 19 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1200.c | 61 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1300.c | 9 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/db1550.c | 27 | ||||
-rw-r--r-- | arch/mips/alchemy/devboards/pm.c | 39 |
18 files changed, 1307 insertions, 275 deletions
diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index 25a59a23547e..1e3b102389ef 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -85,10 +85,10 @@ void __init board_setup(void) #endif /* IS_ENABLED(CONFIG_USB_OHCI_HCD) */ /* Initialize sys_pinfunc */ - au_writel(SYS_PF_NI2, SYS_PINFUNC); + alchemy_wrsys(SYS_PF_NI2, AU1000_SYS_PINFUNC); /* Initialize GPIO */ - au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR); + alchemy_wrsys(~0, AU1000_SYS_TRIOUTCLR); alchemy_gpio_direction_output(0, 0); /* Disable M66EN (PCI 66MHz) */ alchemy_gpio_direction_output(3, 1); /* Disable PCI CLKRUN# */ alchemy_gpio_direction_output(1, 1); /* Enable EXT_IO3 */ diff --git a/arch/mips/alchemy/board-xxs1500.c b/arch/mips/alchemy/board-xxs1500.c index 3fb814be0e91..0fc53e08a894 100644 --- a/arch/mips/alchemy/board-xxs1500.c +++ b/arch/mips/alchemy/board-xxs1500.c @@ -87,9 +87,9 @@ void __init board_setup(void) alchemy_gpio2_enable(); /* Set multiple use pins (UART3/GPIO) to UART (it's used as UART too) */ - pin_func = au_readl(SYS_PINFUNC) & ~SYS_PF_UR3; + pin_func = alchemy_rdsys(AU1000_SYS_PINFUNC) & ~SYS_PF_UR3; pin_func |= SYS_PF_UR3; - au_writel(pin_func, SYS_PINFUNC); + alchemy_wrsys(pin_func, AU1000_SYS_PINFUNC); /* Enable UART */ alchemy_uart_enable(AU1000_UART3_PHYS_ADDR); diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index cb83d8d21aef..f64744f3b59f 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -5,8 +5,8 @@ # Makefile for the Alchemy Au1xx0 CPUs, generic files. # -obj-y += prom.o time.o clocks.o platform.o power.o setup.o \ - sleeper.o dma.o dbdma.o vss.o irq.o usb.o +obj-y += prom.o time.o clock.o platform.o power.o \ + setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o # optional gpiolib support ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) diff --git a/arch/mips/alchemy/common/clock.c b/arch/mips/alchemy/common/clock.c new file mode 100644 index 000000000000..d7557cde271a --- /dev/null +++ b/arch/mips/alchemy/common/clock.c @@ -0,0 +1,1094 @@ +/* + * Alchemy clocks. + * + * Exposes all configurable internal clock sources to the clk framework. + * + * We have: + * - Root source, usually 12MHz supplied by an external crystal + * - 3 PLLs which generate multiples of root rate [AUX, CPU, AUX2] + * + * Dividers: + * - 6 clock dividers with: + * * selectable source [one of the PLLs], + * * output divided between [2 .. 512 in steps of 2] (!Au1300) + * or [1 .. 256 in steps of 1] (Au1300), + * * can be enabled individually. + * + * - up to 6 "internal" (fixed) consumers which: + * * take either AUXPLL or one of the above 6 dividers as input, + * * divide this input by 1, 2, or 4 (and 3 on Au1300). + * * can be disabled separately. + * + * Misc clocks: + * - sysbus clock: CPU core clock (CPUPLL) divided by 2, 3 or 4. + * depends on board design and should be set by bootloader, read-only. + * - peripheral clock: half the rate of sysbus clock, source for a lot + * of peripheral blocks, read-only. + * - memory clock: clk rate to main memory chips, depends on board + * design and is read-only, + * - lrclk: the static bus clock signal for synchronous operation. + * depends on board design, must be set by bootloader, + * but may be required to correctly configure devices attached to + * the static bus. The Au1000/1500/1100 manuals call it LCLK, on + * later models it's called RCLK. + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/clk-private.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <asm/mach-au1x00/au1000.h> + +/* Base clock: 12MHz is the default in all databooks, and I haven't + * found any board yet which uses a different rate. + */ +#define ALCHEMY_ROOTCLK_RATE 12000000 + +/* + * the internal sources which can be driven by the PLLs and dividers. + * Names taken from the databooks, refer to them for more information, + * especially which ones are share a clock line. + */ +static const char * const alchemy_au1300_intclknames[] = { + "lcd_intclk", "gpemgp_clk", "maempe_clk", "maebsa_clk", + "EXTCLK0", "EXTCLK1" +}; + +static const char * const alchemy_au1200_intclknames[] = { + "lcd_intclk", NULL, NULL, NULL, "EXTCLK0", "EXTCLK1" +}; + +static const char * const alchemy_au1550_intclknames[] = { + "usb_clk", "psc0_intclk", "psc1_intclk", "pci_clko", + "EXTCLK0", "EXTCLK1" +}; + +static const char * const alchemy_au1100_intclknames[] = { + "usb_clk", "lcd_intclk", NULL, "i2s_clk", "EXTCLK0", "EXTCLK1" +}; + +static const char * const alchemy_au1500_intclknames[] = { + NULL, "usbd_clk", "usbh_clk", "pci_clko", "EXTCLK0", "EXTCLK1" +}; + +static const char * const alchemy_au1000_intclknames[] = { + "irda_clk", "usbd_clk", "usbh_clk", "i2s_clk", "EXTCLK0", + "EXTCLK1" +}; + +/* aliases for a few on-chip sources which are either shared + * or have gone through name changes. + */ +static struct clk_aliastable { + char *alias; + char *base; + int cputype; +} alchemy_clk_aliases[] __initdata = { + { "usbh_clk", "usb_clk", ALCHEMY_CPU_AU1100 }, + { "usbd_clk", "usb_clk", ALCHEMY_CPU_AU1100 }, + { "irda_clk", "usb_clk", ALCHEMY_CPU_AU1100 }, + { "usbh_clk", "usb_clk", ALCHEMY_CPU_AU1550 }, + { "usbd_clk", "usb_clk", ALCHEMY_CPU_AU1550 }, + { "psc2_intclk", "usb_clk", ALCHEMY_CPU_AU1550 }, + { "psc3_intclk", "EXTCLK0", ALCHEMY_CPU_AU1550 }, + { "psc0_intclk", "EXTCLK0", ALCHEMY_CPU_AU1200 }, + { "psc1_intclk", "EXTCLK1", ALCHEMY_CPU_AU1200 }, + { "psc0_intclk", "EXTCLK0", ALCHEMY_CPU_AU1300 }, + { "psc2_intclk", "EXTCLK0", ALCHEMY_CPU_AU1300 }, + { "psc1_intclk", "EXTCLK1", ALCHEMY_CPU_AU1300 }, + { "psc3_intclk", "EXTCLK1", ALCHEMY_CPU_AU1300 }, + + { NULL, NULL, 0 }, +}; + +#define IOMEM(x) ((void __iomem *)(KSEG1ADDR(CPHYSADDR(x)))) + +/* access locks to SYS_FREQCTRL0/1 and SYS_CLKSRC registers */ +static spinlock_t alchemy_clk_fg0_lock; +static spinlock_t alchemy_clk_fg1_lock; +static spinlock_t alchemy_clk_csrc_lock; + +/* CPU Core clock *****************************************************/ + +static unsigned long alchemy_clk_cpu_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned long t; + + /* + * On early Au1000, sys_cpupll was write-only. Since these + * silicon versions of Au1000 are not sold, we don't bend + * over backwards trying to determine the frequency. + */ + if (unlikely(au1xxx_cpu_has_pll_wo())) + t = 396000000; + else { + t = alchemy_rdsys(AU1000_SYS_CPUPLL) & 0x7f; + t *= parent_rate; + } + + return t; +} + +static struct clk_ops alchemy_clkops_cpu = { + .recalc_rate = alchemy_clk_cpu_recalc, +}; + +static struct clk __init *alchemy_clk_setup_cpu(const char *parent_name, + int ctype) +{ + struct clk_init_data id; + struct clk_hw *h; + + h = kzalloc(sizeof(*h), GFP_KERNEL); + if (!h) + return ERR_PTR(-ENOMEM); + + id.name = ALCHEMY_CPU_CLK; + id.parent_names = &parent_name; + id.num_parents = 1; + id.flags = CLK_IS_BASIC; + id.ops = &alchemy_clkops_cpu; + h->init = &id; + + return clk_register(NULL, h); +} + +/* AUXPLLs ************************************************************/ + +struct alchemy_auxpll_clk { + struct clk_hw hw; + unsigned long reg; /* au1300 has also AUXPLL2 */ + int maxmult; /* max multiplier */ +}; +#define to_auxpll_clk(x) container_of(x, struct alchemy_auxpll_clk, hw) + +static unsigned long alchemy_clk_aux_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); + + return (alchemy_rdsys(a->reg) & 0xff) * parent_rate; +} + +static int alchemy_clk_aux_setr(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); + unsigned long d = rate; + + if (rate) + d /= parent_rate; + else + d = 0; + + /* minimum is 84MHz, max is 756-1032 depending on variant */ + if (((d < 7) && (d != 0)) || (d > a->maxmult)) + return -EINVAL; + + alchemy_wrsys(d, a->reg); + return 0; +} + +static long alchemy_clk_aux_roundr(struct clk_hw *hw, + unsigned long rate, + unsigned long *parent_rate) +{ + struct alchemy_auxpll_clk *a = to_auxpll_clk(hw); + unsigned long mult; + + if (!rate || !*parent_rate) + return 0; + + mult = rate / (*parent_rate); + + if (mult && (mult < 7)) + mult = 7; + if (mult > a->maxmult) + mult = a->maxmult; + + return (*parent_rate) * mult; +} + +static struct clk_ops alchemy_clkops_aux = { + .recalc_rate = alchemy_clk_aux_recalc, + .set_rate = alchemy_clk_aux_setr, + .round_rate = alchemy_clk_aux_roundr, +}; + +static struct clk __init *alchemy_clk_setup_aux(const char *parent_name, + char *name, int maxmult, + unsigned long reg) +{ + struct clk_init_data id; + struct clk *c; + struct alchemy_auxpll_clk *a; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return ERR_PTR(-ENOMEM); + + id.name = name; + id.parent_names = &parent_name; + id.num_parents = 1; + id.flags = CLK_GET_RATE_NOCACHE; + id.ops = &alchemy_clkops_aux; + + a->reg = reg; + a->maxmult = maxmult; + a->hw.init = &id; + + c = clk_register(NULL, &a->hw); + if (!IS_ERR(c)) + clk_register_clkdev(c, name, NULL); + else + kfree(a); + + return c; +} + +/* sysbus_clk *********************************************************/ + +static struct clk __init *alchemy_clk_setup_sysbus(const char *pn) +{ + unsigned long v = (alchemy_rdsys(AU1000_SYS_POWERCTRL) & 3) + 2; + struct clk *c; + + c = clk_register_fixed_factor(NULL, ALCHEMY_SYSBUS_CLK, + pn, 0, 1, v); + if (!IS_ERR(c)) + clk_register_clkdev(c, ALCHEMY_SYSBUS_CLK, NULL); + return c; +} + +/* Peripheral Clock ***************************************************/ + +static struct clk __init *alchemy_clk_setup_periph(const char *pn) +{ + /* Peripheral clock runs at half the rate of sysbus clk */ + struct clk *c; + + c = clk_register_fixed_factor(NULL, ALCHEMY_PERIPH_CLK, + pn, 0, 1, 2); + if (!IS_ERR(c)) + clk_register_clkdev(c, ALCHEMY_PERIPH_CLK, NULL); + return c; +} + +/* mem clock **********************************************************/ + +static struct clk __init *alchemy_clk_setup_mem(const char *pn, int ct) +{ + void __iomem *addr = IOMEM(AU1000_MEM_PHYS_ADDR); + unsigned long v; + struct clk *c; + int div; + + switch (ct) { + case ALCHEMY_CPU_AU1550: + case ALCHEMY_CPU_AU1200: + v = __raw_readl(addr + AU1550_MEM_SDCONFIGB); + div = (v & (1 << 15)) ? 1 : 2; + break; + case ALCHEMY_CPU_AU1300: + v = __raw_readl(addr + AU1550_MEM_SDCONFIGB); + div = (v & (1 << 31)) ? 1 : 2; + break; + case ALCHEMY_CPU_AU1000: + case ALCHEMY_CPU_AU1500: + case ALCHEMY_CPU_AU1100: + default: + div = 2; + break; + } + + c = clk_register_fixed_factor(NULL, ALCHEMY_MEM_CLK, pn, + 0, 1, div); + if (!IS_ERR(c)) + clk_register_clkdev(c, ALCHEMY_MEM_CLK, NULL); + return c; +} + +/* lrclk: external synchronous static bus clock ***********************/ + +static struct clk __init *alchemy_clk_setup_lrclk(const char *pn) +{ + /* MEM_STCFG0[15:13] = divisor. + * L/RCLK = periph_clk / (divisor + 1) + * On Au1000, Au1500, Au1100 it's called LCLK, + * on later models it's called RCLK, but it's the same thing. + */ + struct clk *c; + unsigned long v = alchemy_rdsmem(AU1000_MEM_STCFG0) >> 13; + + v = (v & 7) + 1; + c = clk_register_fixed_factor(NULL, ALCHEMY_LR_CLK, + pn, 0, 1, v); + if (!IS_ERR(c)) + clk_register_clkdev(c, ALCHEMY_LR_CLK, NULL); + return c; +} + +/* Clock dividers and muxes *******************************************/ + +/* data for fgen and csrc mux-dividers */ +struct alchemy_fgcs_clk { + struct clk_hw hw; + spinlock_t *reglock; /* register lock */ + unsigned long reg; /* SYS_FREQCTRL0/1 */ + int shift; /* offset in register */ + int parent; /* parent before disable [Au1300] */ + int isen; /* is it enabled? */ + int *dt; /* dividertable for csrc */ +}; +#define to_fgcs_clk(x) container_of(x, struct alchemy_fgcs_clk, hw) + +static long alchemy_calc_div(unsigned long rate, unsigned long prate, + int scale, int maxdiv, unsigned long *rv) +{ + long div1, div2; + + div1 = prate / rate; + if ((prate / div1) > rate) + div1++; + + if (scale == 2) { /* only div-by-multiple-of-2 possible */ + if (div1 & 1) + div1++; /* stay <=prate */ + } + + div2 = (div1 / scale) - 1; /* value to write to register */ + + if (div2 > maxdiv) + div2 = maxdiv; + if (rv) + *rv = div2; + + div1 = ((div2 + 1) * scale); + return div1; +} + +static long alchemy_clk_fgcs_detr(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk, + int scale, int maxdiv) +{ + struct clk *pc, *bpc, *free; + long tdv, tpr, pr, nr, br, bpr, diff, lastdiff; + int j; + + lastdiff = INT_MAX; + bpr = 0; + bpc = NULL; + br = -EINVAL; + free = NULL; + + /* look at the rates each enabled parent supplies and select + * the one that gets closest to but not over the requested rate. + */ + for (j = 0; j < 7; j++) { + pc = clk_get_parent_by_index(hw->clk, j); + if (!pc) + break; + + /* if this parent is currently unused, remember it. + * XXX: I know it's a layering violation, but it works + * so well.. (if (!clk_has_active_children(pc)) ) + */ + if (pc->prepare_count == 0) { + if (!free) + free = pc; + } + + pr = clk_get_rate(pc); + if (pr < rate) + continue; + + /* what can hardware actually provide */ + tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + nr = pr / tdv; + diff = rate - nr; + if (nr > rate) + continue; + + if (diff < lastdiff) { + lastdiff = diff; + bpr = pr; + bpc = pc; + br = nr; + } + if (diff == 0) + break; + } + + /* if we couldn't get the exact rate we wanted from the enabled + * parents, maybe we can tell an available disabled/inactive one + * to give us a rate we can divide down to the requested rate. + */ + if (lastdiff && free) { + for (j = (maxdiv == 4) ? 1 : scale; j <= maxdiv; j += scale) { + tpr = rate * j; + if (tpr < 0) + break; + pr = clk_round_rate(free, tpr); + + tdv = alchemy_calc_div(rate, pr, scale, maxdiv, NULL); + nr = pr / tdv; + diff = rate - nr; + if (nr > rate) + continue; + if (diff < lastdiff) { + lastdiff = diff; + bpr = pr; + bpc = free; + br = nr; + } + if (diff == 0) + break; + } + } + + *best_parent_rate = bpr; + *best_parent_clk = bpc; + return br; +} + +static int alchemy_clk_fgv1_en(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v, flags; + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v |= (1 << 1) << c->shift; + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static int alchemy_clk_fgv1_isen(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 1); + + return v & 1; +} + +static void alchemy_clk_fgv1_dis(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v, flags; + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~((1 << 1) << c->shift); + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); +} + +static int alchemy_clk_fgv1_setp(struct clk_hw *hw, u8 index) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v, flags; + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + if (index) + v |= (1 << c->shift); + else + v &= ~(1 << c->shift); + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static u8 alchemy_clk_fgv1_getp(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + + return (alchemy_rdsys(c->reg) >> c->shift) & 1; +} + +static int alchemy_clk_fgv1_setr(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long div, v, flags, ret; + int sh = c->shift + 2; + + if (!rate || !parent_rate || rate > (parent_rate / 2)) + return -EINVAL; + ret = alchemy_calc_div(rate, parent_rate, 2, 512, &div); + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~(0xff << sh); + v |= div << sh; + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static unsigned long alchemy_clk_fgv1_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v = alchemy_rdsys(c->reg) >> (c->shift + 2); + + v = ((v & 0xff) + 1) * 2; + return parent_rate / v; +} + +static long alchemy_clk_fgv1_detr(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, + best_parent_clk, 2, 512); +} + +/* Au1000, Au1100, Au15x0, Au12x0 */ +static struct clk_ops alchemy_clkops_fgenv1 = { + .recalc_rate = alchemy_clk_fgv1_recalc, + .determine_rate = alchemy_clk_fgv1_detr, + .set_rate = alchemy_clk_fgv1_setr, + .set_parent = alchemy_clk_fgv1_setp, + .get_parent = alchemy_clk_fgv1_getp, + .enable = alchemy_clk_fgv1_en, + .disable = alchemy_clk_fgv1_dis, + .is_enabled = alchemy_clk_fgv1_isen, +}; + +static void __alchemy_clk_fgv2_en(struct alchemy_fgcs_clk *c) +{ + unsigned long v = alchemy_rdsys(c->reg); + + v &= ~(3 << c->shift); + v |= (c->parent & 3) << c->shift; + alchemy_wrsys(v, c->reg); + c->isen = 1; +} + +static int alchemy_clk_fgv2_en(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long flags; + + /* enable by setting the previous parent clock */ + spin_lock_irqsave(c->reglock, flags); + __alchemy_clk_fgv2_en(c); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static int alchemy_clk_fgv2_isen(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + + return ((alchemy_rdsys(c->reg) >> c->shift) & 3) != 0; +} + +static void alchemy_clk_fgv2_dis(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v, flags; + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~(3 << c->shift); /* set input mux to "disabled" state */ + alchemy_wrsys(v, c->reg); + c->isen = 0; + spin_unlock_irqrestore(c->reglock, flags); +} + +static int alchemy_clk_fgv2_setp(struct clk_hw *hw, u8 index) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long flags; + + spin_lock_irqsave(c->reglock, flags); + c->parent = index + 1; /* value to write to register */ + if (c->isen) + __alchemy_clk_fgv2_en(c); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static u8 alchemy_clk_fgv2_getp(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long flags, v; + + spin_lock_irqsave(c->reglock, flags); + v = c->parent - 1; + spin_unlock_irqrestore(c->reglock, flags); + return v; +} + +/* fg0-2 and fg4-6 share a "scale"-bit. With this bit cleared, the + * dividers behave exactly as on previous models (dividers are multiples + * of 2); with the bit set, dividers are multiples of 1, halving their + * range, but making them also much more flexible. + */ +static int alchemy_clk_fgv2_setr(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + int sh = c->shift + 2; + unsigned long div, v, flags, ret; + + if (!rate || !parent_rate || rate > parent_rate) + return -EINVAL; + + v = alchemy_rdsys(c->reg) & (1 << 30); /* test "scale" bit */ + ret = alchemy_calc_div(rate, parent_rate, v ? 1 : 2, + v ? 256 : 512, &div); + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~(0xff << sh); + v |= (div & 0xff) << sh; + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static unsigned long alchemy_clk_fgv2_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + int sh = c->shift + 2; + unsigned long v, t; + + v = alchemy_rdsys(c->reg); + t = parent_rate / (((v >> sh) & 0xff) + 1); + if ((v & (1 << 30)) == 0) /* test scale bit */ + t /= 2; + + return t; +} + +static long alchemy_clk_fgv2_detr(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + int scale, maxdiv; + + if (alchemy_rdsys(c->reg) & (1 << 30)) { + scale = 1; + maxdiv = 256; + } else { + scale = 2; + maxdiv = 512; + } + + return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, + best_parent_clk, scale, maxdiv); +} + +/* Au1300 larger input mux, no separate disable bit, flexible divider */ +static struct clk_ops alchemy_clkops_fgenv2 = { + .recalc_rate = alchemy_clk_fgv2_recalc, + .determine_rate = alchemy_clk_fgv2_detr, + .set_rate = alchemy_clk_fgv2_setr, + .set_parent = alchemy_clk_fgv2_setp, + .get_parent = alchemy_clk_fgv2_getp, + .enable = alchemy_clk_fgv2_en, + .disable = alchemy_clk_fgv2_dis, + .is_enabled = alchemy_clk_fgv2_isen, +}; + +static const char * const alchemy_clk_fgv1_parents[] = { + ALCHEMY_CPU_CLK, ALCHEMY_AUXPLL_CLK +}; + +static const char * const alchemy_clk_fgv2_parents[] = { + ALCHEMY_AUXPLL2_CLK, ALCHEMY_CPU_CLK, ALCHEMY_AUXPLL_CLK +}; + +static const char * const alchemy_clk_fgen_names[] = { + ALCHEMY_FG0_CLK, ALCHEMY_FG1_CLK, ALCHEMY_FG2_CLK, + ALCHEMY_FG3_CLK, ALCHEMY_FG4_CLK, ALCHEMY_FG5_CLK }; + +static int __init alchemy_clk_init_fgens(int ctype) +{ + struct clk *c; + struct clk_init_data id; + struct alchemy_fgcs_clk *a; + unsigned long v; + int i, ret; + + switch (ctype) { + case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200: + id.ops = &alchemy_clkops_fgenv1; + id.parent_names = (const char **)alchemy_clk_fgv1_parents; + id.num_parents = 2; + break; + case ALCHEMY_CPU_AU1300: + id.ops = &alchemy_clkops_fgenv2; + id.parent_names = (const char **)alchemy_clk_fgv2_parents; + id.num_parents = 3; + break; + default: + return -ENODEV; + } + id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; + + a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL); + if (!a) + return -ENOMEM; + + spin_lock_init(&alchemy_clk_fg0_lock); + spin_lock_init(&alchemy_clk_fg1_lock); + ret = 0; + for (i = 0; i < 6; i++) { + id.name = alchemy_clk_fgen_names[i]; + a->shift = 10 * (i < 3 ? i : i - 3); + if (i > 2) { + a->reg = AU1000_SYS_FREQCTRL1; + a->reglock = &alchemy_clk_fg1_lock; + } else { + a->reg = AU1000_SYS_FREQCTRL0; + a->reglock = &alchemy_clk_fg0_lock; + } + + /* default to first parent if bootloader has set + * the mux to disabled state. + */ + if (ctype == ALCHEMY_CPU_AU1300) { + v = alchemy_rdsys(a->reg); + a->parent = (v >> a->shift) & 3; + if (!a->parent) { + a->parent = 1; + a->isen = 0; + } else + a->isen = 1; + } + + a->hw.init = &id; + c = clk_register(NULL, &a->hw); + if (IS_ERR(c)) + ret++; + else + clk_register_clkdev(c, id.name, NULL); + a++; + } + + return ret; +} + +/* internal sources muxes *********************************************/ + +static int alchemy_clk_csrc_isen(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v = alchemy_rdsys(c->reg); + + return (((v >> c->shift) >> 2) & 7) != 0; +} + +static void __alchemy_clk_csrc_en(struct alchemy_fgcs_clk *c) +{ + unsigned long v = alchemy_rdsys(c->reg); + + v &= ~((7 << 2) << c->shift); + v |= ((c->parent & 7) << 2) << c->shift; + alchemy_wrsys(v, c->reg); + c->isen = 1; +} + +static int alchemy_clk_csrc_en(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long flags; + + /* enable by setting the previous parent clock */ + spin_lock_irqsave(c->reglock, flags); + __alchemy_clk_csrc_en(c); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static void alchemy_clk_csrc_dis(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v, flags; + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~((3 << 2) << c->shift); /* mux to "disabled" state */ + alchemy_wrsys(v, c->reg); + c->isen = 0; + spin_unlock_irqrestore(c->reglock, flags); +} + +static int alchemy_clk_csrc_setp(struct clk_hw *hw, u8 index) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long flags; + + spin_lock_irqsave(c->reglock, flags); + c->parent = index + 1; /* value to write to register */ + if (c->isen) + __alchemy_clk_csrc_en(c); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static u8 alchemy_clk_csrc_getp(struct clk_hw *hw) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + + return c->parent - 1; +} + +static unsigned long alchemy_clk_csrc_recalc(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long v = (alchemy_rdsys(c->reg) >> c->shift) & 3; + + return parent_rate / c->dt[v]; +} + +static int alchemy_clk_csrc_setr(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + unsigned long d, v, flags; + int i; + + if (!rate || !parent_rate || rate > parent_rate) + return -EINVAL; + + d = (parent_rate + (rate / 2)) / rate; + if (d > 4) + return -EINVAL; + if ((d == 3) && (c->dt[2] != 3)) + d = 4; + + for (i = 0; i < 4; i++) + if (c->dt[i] == d) + break; + + if (i >= 4) + return -EINVAL; /* oops */ + + spin_lock_irqsave(c->reglock, flags); + v = alchemy_rdsys(c->reg); + v &= ~(3 << c->shift); + v |= (i & 3) << c->shift; + alchemy_wrsys(v, c->reg); + spin_unlock_irqrestore(c->reglock, flags); + + return 0; +} + +static long alchemy_clk_csrc_detr(struct clk_hw *hw, unsigned long rate, + unsigned long *best_parent_rate, + struct clk **best_parent_clk) +{ + struct alchemy_fgcs_clk *c = to_fgcs_clk(hw); + int scale = c->dt[2] == 3 ? 1 : 2; /* au1300 check */ + + return alchemy_clk_fgcs_detr(hw, rate, best_parent_rate, + best_parent_clk, scale, 4); +} + +static struct clk_ops alchemy_clkops_csrc = { + .recalc_rate = alchemy_clk_csrc_recalc, + .determine_rate = alchemy_clk_csrc_detr, + .set_rate = alchemy_clk_csrc_setr, + .set_parent = alchemy_clk_csrc_setp, + .get_parent = alchemy_clk_csrc_getp, + .enable = alchemy_clk_csrc_en, + .disable = alchemy_clk_csrc_dis, + .is_enabled = alchemy_clk_csrc_isen, +}; + +static const char * const alchemy_clk_csrc_parents[] = { + /* disabled at index 0 */ ALCHEMY_AUXPLL_CLK, + ALCHEMY_FG0_CLK, ALCHEMY_FG1_CLK, ALCHEMY_FG2_CLK, + ALCHEMY_FG3_CLK, ALCHEMY_FG4_CLK, ALCHEMY_FG5_CLK +}; + +/* divider tables */ +static int alchemy_csrc_dt1[] = { 1, 4, 1, 2 }; /* rest */ +static int alchemy_csrc_dt2[] = { 1, 4, 3, 2 }; /* Au1300 */ + +static int __init alchemy_clk_setup_imux(int ctype) +{ + struct alchemy_fgcs_clk *a; + const char * const *names; + struct clk_init_data id; + unsigned long v; + int i, ret, *dt; + struct clk *c; + + id.ops = &alchemy_clkops_csrc; + id.parent_names = (const char **)alchemy_clk_csrc_parents; + id.num_parents = 7; + id.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE; + + dt = alchemy_csrc_dt1; + switch (ctype) { + case ALCHEMY_CPU_AU1000: + names = alchemy_au1000_intclknames; + break; + case ALCHEMY_CPU_AU1500: + names = alchemy_au1500_intclknames; + break; + case ALCHEMY_CPU_AU1100: + names = alchemy_au1100_intclknames; + break; + case ALCHEMY_CPU_AU1550: + names = alchemy_au1550_intclknames; + break; + case ALCHEMY_CPU_AU1200: + names = alchemy_au1200_intclknames; + break; + case ALCHEMY_CPU_AU1300: + dt = alchemy_csrc_dt2; + names = alchemy_au1300_intclknames; + break; + default: + return -ENODEV; + } + + a = kzalloc((sizeof(*a)) * 6, GFP_KERNEL); + if (!a) + return -ENOMEM; + + spin_lock_init(&alchemy_clk_csrc_lock); + ret = 0; + + for (i = 0; i < 6; i++) { + id.name = names[i]; + if (!id.name) + goto next; + + a->shift = i * 5; + a->reg = AU1000_SYS_CLKSRC; + a->reglock = &alchemy_clk_csrc_lock; + a->dt = dt; + + /* default to first parent clock if mux is initially + * set to disabled state. + */ + v = alchemy_rdsys(a->reg); + a->parent = ((v >> a->shift) >> 2) & 7; + if (!a->parent) { + a->parent = 1; + a->isen = 0; + } else + a->isen = 1; + + a->hw.init = &id; + c = clk_register(NULL, &a->hw); + if (IS_ERR(c)) + ret++; + else + clk_register_clkdev(c, id.name, NULL); +next: + a++; + } + + return ret; +} + + +/**********************************************************************/ + + +#define ERRCK(x) \ + if (IS_ERR(x)) { \ + ret = PTR_ERR(x); \ + goto out; \ + } + +static int __init alchemy_clk_init(void) +{ + int ctype = alchemy_get_cputype(), ret, i; + struct clk_aliastable *t = alchemy_clk_aliases; + struct clk *c; + + /* Root of the Alchemy clock tree: external 12MHz crystal osc */ + c = clk_register_fixed_rate(NULL, ALCHEMY_ROOT_CLK, NULL, + CLK_IS_ROOT, + ALCHEMY_ROOTCLK_RATE); + ERRCK(c) + + /* CPU core clock */ + c = alchemy_clk_setup_cpu(ALCHEMY_ROOT_CLK, ctype); + ERRCK(c) + + /* AUXPLLs: max 1GHz on Au1300, 748MHz on older models */ + i = (ctype == ALCHEMY_CPU_AU1300) ? 84 : 63; + c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK, ALCHEMY_AUXPLL_CLK, + i, AU1000_SYS_AUXPLL); + ERRCK(c) + + if (ctype == ALCHEMY_CPU_AU1300) { + c = alchemy_clk_setup_aux(ALCHEMY_ROOT_CLK, + ALCHEMY_AUXPLL2_CLK, i, + AU1300_SYS_AUXPLL2); + ERRCK(c) + } + + /* sysbus clock: cpu core clock divided by 2, 3 or 4 */ + c = alchemy_clk_setup_sysbus(ALCHEMY_CPU_CLK); + ERRCK(c) + + /* peripheral clock: runs at half rate of sysbus clk */ + c = alchemy_clk_setup_periph(ALCHEMY_SYSBUS_CLK); + ERRCK(c) + + /* SDR/DDR memory clock */ + c = alchemy_clk_setup_mem(ALCHEMY_SYSBUS_CLK, ctype); + ERRCK(c) + + /* L/RCLK: external static bus clock for synchronous mode */ + c = alchemy_clk_setup_lrclk(ALCHEMY_PERIPH_CLK); + ERRCK(c) + + /* Frequency dividers 0-5 */ + ret = alchemy_clk_init_fgens(ctype); + if (ret) { + ret = -ENODEV; + goto out; + } + + /* diving muxes for internal sources */ + ret = alchemy_clk_setup_imux(ctype); + if (ret) { + ret = -ENODEV; + goto out; + } + + /* set up aliases drivers might look for */ + while (t->base) { + if (t->cputype == ctype) + clk_add_alias(t->alias, NULL, t->base, NULL); + t++; + } + + pr_info("Alchemy clocktree installed\n"); + return 0; + +out: + return ret; +} +postcore_initcall(alchemy_clk_init); diff --git a/arch/mips/alchemy/common/clocks.c b/arch/mips/alchemy/common/clocks.c deleted file mode 100644 index f38298a8b98c..000000000000 --- a/arch/mips/alchemy/common/clocks.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * BRIEF MODULE DESCRIPTION - * Simple Au1xx0 clocks routines. - * - * Copyright 2001, 2008 MontaVista Software Inc. - * Author: MontaVista Software, Inc. <source@mvista.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include <linux/module.h> -#include <linux/spinlock.h> -#include <asm/time.h> -#include <asm/mach-au1x00/au1000.h> - -/* - * I haven't found anyone that doesn't use a 12 MHz source clock, - * but just in case..... - */ -#define AU1000_SRC_CLK 12000000 - -static unsigned int au1x00_clock; /* Hz */ -static unsigned long uart_baud_base; - -/* - * Set the au1000_clock - */ -void set_au1x00_speed(unsigned int new_freq) -{ - au1x00_clock = new_freq; -} - -unsigned int get_au1x00_speed(void) -{ - return au1x00_clock; -} -EXPORT_SYMBOL(get_au1x00_speed); - -/* - * The UART baud base is not known at compile time ... if - * we want to be able to use the same code on different - * speed CPUs. - */ -unsigned long get_au1x00_uart_baud_base(void) -{ - return uart_baud_base; -} - -void set_au1x00_uart_baud_base(unsigned long new_baud_base) -{ - uart_baud_base = new_baud_base; -} - -/* - * We read the real processor speed from the PLL. This is important - * because it is more accurate than computing it from the 32 KHz - * counter, if it exists. If we don't have an accurate processor - * speed, all of the peripherals that derive their clocks based on - * this advertised speed will introduce error and sometimes not work - * properly. This function is further convoluted to still allow configurations - * to do that in case they have really, really old silicon with a - * write-only PLL register. -- Dan - */ -unsigned long au1xxx_calc_clock(void) -{ - unsigned long cpu_speed; - - /* - * On early Au1000, sys_cpupll was write-only. Since these - * silicon versions of Au1000 are not sold by AMD, we don't bend - * over backwards trying to determine the frequency. - */ - if (au1xxx_cpu_has_pll_wo()) - cpu_speed = 396000000; - else - cpu_speed = (au_readl(SYS_CPUPLL) & 0x0000003f) * AU1000_SRC_CLK; - - /* On Alchemy CPU:counter ratio is 1:1 */ - mips_hpt_frequency = cpu_speed; - /* Equation: Baudrate = CPU / (SD * 2 * CLKDIV * 16) */ - set_au1x00_uart_baud_base(cpu_speed / (2 * ((int)(au_readl(SYS_POWERCTRL) - & 0x03) + 2) * 16)); - - set_au1x00_speed(cpu_speed); - - return cpu_speed; -} diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c index 19d5642c16d9..745695db5ba0 100644 --- a/arch/mips/alchemy/common/dbdma.c +++ b/arch/mips/alchemy/common/dbdma.c @@ -341,7 +341,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, (dtp->dev_flags & DEV_FLAGS_SYNC)) i |= DDMA_CFG_SYNC; cp->ddma_cfg = i; - au_sync(); + wmb(); /* drain writebuffer */ /* * Return a non-zero value that can be used to find the channel @@ -631,7 +631,7 @@ u32 au1xxx_dbdma_put_source(u32 chanid, dma_addr_t buf, int nbytes, u32 flags) */ dma_cache_wback_inv((unsigned long)buf, nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ - au_sync(); + wmb(); /* drain writebuffer */ dma_cache_wback_inv((unsigned long)dp, sizeof(*dp)); ctp->chan_ptr->ddma_dbell = 0; @@ -693,7 +693,7 @@ u32 au1xxx_dbdma_put_dest(u32 chanid, dma_addr_t buf, int nbytes, u32 flags) */ dma_cache_inv((unsigned long)buf, nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ - au_sync(); + wmb(); /* drain writebuffer */ dma_cache_wback_inv((unsigned long)dp, sizeof(*dp)); ctp->chan_ptr->ddma_dbell = 0; @@ -760,7 +760,7 @@ void au1xxx_dbdma_stop(u32 chanid) cp = ctp->chan_ptr; cp->ddma_cfg &= ~DDMA_CFG_EN; /* Disable channel */ - au_sync(); + wmb(); /* drain writebuffer */ while (!(cp->ddma_stat & DDMA_STAT_H)) { udelay(1); halt_timeout++; @@ -771,7 +771,7 @@ void au1xxx_dbdma_stop(u32 chanid) } /* clear current desc valid and doorbell */ cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); - au_sync(); + wmb(); /* drain writebuffer */ } EXPORT_SYMBOL(au1xxx_dbdma_stop); @@ -789,9 +789,9 @@ void au1xxx_dbdma_start(u32 chanid) cp = ctp->chan_ptr; cp->ddma_desptr = virt_to_phys(ctp->cur_ptr); cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */ - au_sync(); + wmb(); /* drain writebuffer */ cp->ddma_dbell = 0; - au_sync(); + wmb(); /* drain writebuffer */ } EXPORT_SYMBOL(au1xxx_dbdma_start); @@ -832,7 +832,7 @@ u32 au1xxx_get_dma_residue(u32 chanid) /* This is only valid if the channel is stopped. */ rv = cp->ddma_bytecnt; - au_sync(); + wmb(); /* drain writebuffer */ return rv; } @@ -868,7 +868,7 @@ static irqreturn_t dbdma_interrupt(int irq, void *dev_id) au1x_dma_chan_t *cp; intstat = dbdma_gptr->ddma_intstat; - au_sync(); + wmb(); /* drain writebuffer */ chan_index = __ffs(intstat); ctp = chan_tab_ptr[chan_index]; @@ -877,7 +877,7 @@ static irqreturn_t dbdma_interrupt(int irq, void *dev_id) /* Reset interrupt. */ cp->ddma_irq = 0; - au_sync(); + wmb(); /* drain writebuffer */ if (ctp->chan_callback) ctp->chan_callback(irq, ctp->chan_callparam); @@ -1061,7 +1061,7 @@ static int __init dbdma_setup(unsigned int irq, dbdev_tab_t *idtable) dbdma_gptr->ddma_config = 0; dbdma_gptr->ddma_throttle = 0; dbdma_gptr->ddma_inten = 0xffff; - au_sync(); + wmb(); /* drain writebuffer */ ret = request_irq(irq, dbdma_interrupt, 0, "dbdma", (void *)dbdma_gptr); if (ret) diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c index 9b624e2c0fcf..4fb6207b883b 100644 --- a/arch/mips/alchemy/common/dma.c +++ b/arch/mips/alchemy/common/dma.c @@ -141,17 +141,17 @@ void dump_au1000_dma_channel(unsigned int dmanr) printk(KERN_INFO "Au1000 DMA%d Register Dump:\n", dmanr); printk(KERN_INFO " mode = 0x%08x\n", - au_readl(chan->io + DMA_MODE_SET)); + __raw_readl(chan->io + DMA_MODE_SET)); printk(KERN_INFO " addr = 0x%08x\n", - au_readl(chan->io + DMA_PERIPHERAL_ADDR)); + __raw_readl(chan->io + DMA_PERIPHERAL_ADDR)); printk(KERN_INFO " start0 = 0x%08x\n", - au_readl(chan->io + DMA_BUFFER0_START)); + __raw_readl(chan->io + DMA_BUFFER0_START)); printk(KERN_INFO " start1 = 0x%08x\n", - au_readl(chan->io + DMA_BUFFER1_START)); + __raw_readl(chan->io + DMA_BUFFER1_START)); printk(KERN_INFO " count0 = 0x%08x\n", - au_readl(chan->io + DMA_BUFFER0_COUNT)); + __raw_readl(chan->io + DMA_BUFFER0_COUNT)); printk(KERN_INFO " count1 = 0x%08x\n", - au_readl(chan->io + DMA_BUFFER1_COUNT)); + __raw_readl(chan->io + DMA_BUFFER1_COUNT)); } /* @@ -204,7 +204,8 @@ int request_au1000_dma(int dev_id, const char *dev_str, } /* fill it in */ - chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN; + chan->io = (void __iomem *)(KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + + i * DMA_CHANNEL_LEN); chan->dev_id = dev_id; chan->dev_str = dev_str; chan->fifo_addr = dev->fifo_addr; diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 63a71817a00c..6cb60abfdcc9 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -389,13 +389,12 @@ static int au1x_ic1_setwake(struct irq_data *d, unsigned int on) return -EINVAL; local_irq_save(flags); - wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK); + wakemsk = alchemy_rdsys(AU1000_SYS_WAKEMSK); if (on) wakemsk |= 1 << bit; else wakemsk &= ~(1 << bit); - __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK); - wmb(); + alchemy_wrsys(wakemsk, AU1000_SYS_WAKEMSK); local_irq_restore(flags); return 0; diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c index 9837a134a6d6..d77a64f4c78b 100644 --- a/arch/mips/alchemy/common/platform.c +++ b/arch/mips/alchemy/common/platform.c @@ -11,6 +11,7 @@ * warranty of any kind, whether express or implied. */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/etherdevice.h> #include <linux/init.h> @@ -99,10 +100,20 @@ static struct platform_device au1xx0_uart_device = { static void __init alchemy_setup_uarts(int ctype) { - unsigned int uartclk = get_au1x00_uart_baud_base() * 16; + long uartclk; int s = sizeof(struct plat_serial8250_port); int c = alchemy_get_uarts(ctype); struct plat_serial8250_port *ports; + struct clk *clk = clk_get(NULL, ALCHEMY_PERIPH_CLK); + + if (IS_ERR(clk)) + return; + if (clk_prepare_enable(clk)) { + clk_put(clk); + return; + } + uartclk = clk_get_rate(clk); + clk_put(clk); ports = kzalloc(s * (c + 1), GFP_KERNEL); if (!ports) { @@ -420,7 +431,7 @@ static void __init alchemy_setup_macs(int ctype) memcpy(au1xxx_eth1_platform_data.mac, ethaddr, 6); /* Register second MAC if enabled in pinfunc */ - if (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) { + if (!(alchemy_rdsys(AU1000_SYS_PINFUNC) & SYS_PF_NI2)) { ret = platform_device_register(&au1xxx_eth1_device); if (ret) printk(KERN_INFO "Alchemy: failed to register MAC1\n"); diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index bdb28dee8fdd..921ed30b440c 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -54,28 +54,28 @@ static unsigned int sleep_static_memctlr[4][3]; static void save_core_regs(void) { /* Clocks and PLLs. */ - sleep_sys_clocks[0] = au_readl(SYS_FREQCTRL0); - sleep_sys_clocks[1] = au_readl(SYS_FREQCTRL1); - sleep_sys_clocks[2] = au_readl(SYS_CLKSRC); - sleep_sys_clocks[3] = au_readl(SYS_CPUPLL); - sleep_sys_clocks[4] = au_readl(SYS_AUXPLL); + sleep_sys_clocks[0] = alchemy_rdsys(AU1000_SYS_FREQCTRL0); + sleep_sys_clocks[1] = alchemy_rdsys(AU1000_SYS_FREQCTRL1); + sleep_sys_clocks[2] = alchemy_rdsys(AU1000_SYS_CLKSRC); + sleep_sys_clocks[3] = alchemy_rdsys(AU1000_SYS_CPUPLL); + sleep_sys_clocks[4] = alchemy_rdsys(AU1000_SYS_AUXPLL); /* pin mux config */ - sleep_sys_pinfunc = au_readl(SYS_PINFUNC); + sleep_sys_pinfunc = alchemy_rdsys(AU1000_SYS_PINFUNC); /* Save the static memory controller configuration. */ - sleep_static_memctlr[0][0] = au_readl(MEM_STCFG0); - sleep_static_memctlr[0][1] = au_readl(MEM_STTIME0); - sleep_static_memctlr[0][2] = au_readl(MEM_STADDR0); - sleep_static_memctlr[1][0] = au_readl(MEM_STCFG1); - sleep_static_memctlr[1][1] = au_readl(MEM_STTIME1); - sleep_static_memctlr[1][2] = au_readl(MEM_STADDR1); - sleep_static_memctlr[2][0] = au_readl(MEM_STCFG2); - sleep_static_memctlr[2][1] = au_readl(MEM_STTIME2); - sleep_static_memctlr[2][2] = au_readl(MEM_STADDR2); - sleep_static_memctlr[3][0] = au_readl(MEM_STCFG3); - sleep_static_memctlr[3][1] = au_readl(MEM_STTIME3); - sleep_static_memctlr[3][2] = au_readl(MEM_STADDR3); + sleep_static_memctlr[0][0] = alchemy_rdsmem(AU1000_MEM_STCFG0); + sleep_static_memctlr[0][1] = alchemy_rdsmem(AU1000_MEM_STTIME0); + sleep_static_memctlr[0][2] = alchemy_rdsmem(AU1000_MEM_STADDR0); + sleep_static_memctlr[1][0] = alchemy_rdsmem(AU1000_MEM_STCFG1); + sleep_static_memctlr[1][1] = alchemy_rdsmem(AU1000_MEM_STTIME1); + sleep_static_memctlr[1][2] = alchemy_rdsmem(AU1000_MEM_STADDR1); + sleep_static_memctlr[2][0] = alchemy_rdsmem(AU1000_MEM_STCFG2); + sleep_static_memctlr[2][1] = alchemy_rdsmem(AU1000_MEM_STTIME2); + sleep_static_memctlr[2][2] = alchemy_rdsmem(AU1000_MEM_STADDR2); + sleep_static_memctlr[3][0] = alchemy_rdsmem(AU1000_MEM_STCFG3); + sleep_static_memctlr[3][1] = alchemy_rdsmem(AU1000_MEM_STTIME3); + sleep_static_memctlr[3][2] = alchemy_rdsmem(AU1000_MEM_STADDR3); } static void restore_core_regs(void) @@ -85,30 +85,28 @@ static void restore_core_regs(void) * one of those Au1000 with a write-only PLL, where we dont * have a valid value) */ - au_writel(sleep_sys_clocks[0], SYS_FREQCTRL0); - au_writel(sleep_sys_clocks[1], SYS_FREQCTRL1); - au_writel(sleep_sys_clocks[2], SYS_CLKSRC); - au_writel(sleep_sys_clocks[4], SYS_AUXPLL); + alchemy_wrsys(sleep_sys_clocks[0], AU1000_SYS_FREQCTRL0); + alchemy_wrsys(sleep_sys_clocks[1], AU1000_SYS_FREQCTRL1); + alchemy_wrsys(sleep_sys_clocks[2], AU1000_SYS_CLKSRC); + alchemy_wrsys(sleep_sys_clocks[4], AU1000_SYS_AUXPLL); if (!au1xxx_cpu_has_pll_wo()) - au_writel(sleep_sys_clocks[3], SYS_CPUPLL); - au_sync(); + alchemy_wrsys(sleep_sys_clocks[3], AU1000_SYS_CPUPLL); - au_writel(sleep_sys_pinfunc, SYS_PINFUNC); - au_sync(); + alchemy_wrsys(sleep_sys_pinfunc, AU1000_SYS_PINFUNC); /* Restore the static memory controller configuration. */ - au_writel(sleep_static_memctlr[0][0], MEM_STCFG0); - au_writel(sleep_static_memctlr[0][1], MEM_STTIME0); - au_writel(sleep_static_memctlr[0][2], MEM_STADDR0); - au_writel(sleep_static_memctlr[1][0], MEM_STCFG1); - au_writel(sleep_static_memctlr[1][1], MEM_STTIME1); - au_writel(sleep_static_memctlr[1][2], MEM_STADDR1); - au_writel(sleep_static_memctlr[2][0], MEM_STCFG2); - au_writel(sleep_static_memctlr[2][1], MEM_STTIME2); - au_writel(sleep_static_memctlr[2][2], MEM_STADDR2); - au_writel(sleep_static_memctlr[3][0], MEM_STCFG3); - au_writel(sleep_static_memctlr[3][1], MEM_STTIME3); - au_writel(sleep_static_memctlr[3][2], MEM_STADDR3); + alchemy_wrsmem(sleep_static_memctlr[0][0], AU1000_MEM_STCFG0); + alchemy_wrsmem(sleep_static_memctlr[0][1], AU1000_MEM_STTIME0); + alchemy_wrsmem(sleep_static_memctlr[0][2], AU1000_MEM_STADDR0); + alchemy_wrsmem(sleep_static_memctlr[1][0], AU1000_MEM_STCFG1); + alchemy_wrsmem(sleep_static_memctlr[1][1], AU1000_MEM_STTIME1); + alchemy_wrsmem(sleep_static_memctlr[1][2], AU1000_MEM_STADDR1); + alchemy_wrsmem(sleep_static_memctlr[2][0], AU1000_MEM_STCFG2); + alchemy_wrsmem(sleep_static_memctlr[2][1], AU1000_MEM_STTIME2); + alchemy_wrsmem(sleep_static_memctlr[2][2], AU1000_MEM_STADDR2); + alchemy_wrsmem(sleep_static_memctlr[3][0], AU1000_MEM_STCFG3); + alchemy_wrsmem(sleep_static_memctlr[3][1], AU1000_MEM_STTIME3); + alchemy_wrsmem(sleep_static_memctlr[3][2], AU1000_MEM_STADDR3); } void au_sleep(void) diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c index 8267e3c97721..ea8f41869e56 100644 --- a/arch/mips/alchemy/common/setup.c +++ b/arch/mips/alchemy/common/setup.c @@ -27,12 +27,9 @@ #include <linux/init.h> #include <linux/ioport.h> -#include <linux/jiffies.h> -#include <linux/module.h> #include <asm/dma-coherence.h> #include <asm/mipsregs.h> -#include <asm/time.h> #include <au1000.h> @@ -41,18 +38,6 @@ extern void set_cpuspec(void); void __init plat_mem_setup(void) { - unsigned long est_freq; - - /* determine core clock */ - est_freq = au1xxx_calc_clock(); - est_freq += 5000; /* round */ - est_freq -= est_freq % 10000; - printk(KERN_INFO "(PRId %08x) @ %lu.%02lu MHz\n", read_c0_prid(), - est_freq / 1000000, ((est_freq % 1000000) * 100) / 1000000); - - /* this is faster than wasting cycles trying to approximate it */ - preset_lpj = (est_freq >> 1) / HZ; - if (au1xxx_cpu_needs_config_od()) /* Various early Au1xx0 errata corrected by this */ set_c0_config(1 << 19); /* Set Config[OD] */ diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 93fa586d52e2..50e17e13c18b 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -46,7 +46,7 @@ static cycle_t au1x_counter1_read(struct clocksource *cs) { - return au_readl(SYS_RTCREAD); + return alchemy_rdsys(AU1000_SYS_RTCREAD); } static struct clocksource au1x_counter1_clocksource = { @@ -60,12 +60,11 @@ static struct clocksource au1x_counter1_clocksource = { static int au1x_rtcmatch2_set_next_event(unsigned long delta, struct clock_event_device *cd) { - delta += au_readl(SYS_RTCREAD); + delta += alchemy_rdsys(AU1000_SYS_RTCREAD); /* wait for register access */ - while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M21) + while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M21) ; - au_writel(delta, SYS_RTCMATCH2); - au_sync(); + alchemy_wrsys(delta, AU1000_SYS_RTCMATCH2); return 0; } @@ -112,31 +111,29 @@ static int __init alchemy_time_init(unsigned int m2int) * (the 32S bit seems to be stuck set to 1 once a single clock- * edge is detected, hence the timeouts). */ - if (CNTR_OK != (au_readl(SYS_COUNTER_CNTRL) & CNTR_OK)) + if (CNTR_OK != (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & CNTR_OK)) goto cntr_err; /* * setup counter 1 (RTC) to tick at full speed */ t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && --t) + while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_T1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; - au_writel(0, SYS_RTCTRIM); /* 32.768 kHz */ - au_sync(); + alchemy_wrsys(0, AU1000_SYS_RTCTRIM); /* 32.768 kHz */ t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t) + while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; - au_writel(0, SYS_RTCWRITE); - au_sync(); + alchemy_wrsys(0, AU1000_SYS_RTCWRITE); t = 0xffffff; - while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t) + while ((alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_C1S) && --t) asm volatile ("nop"); if (!t) goto cntr_err; diff --git a/arch/mips/alchemy/common/usb.c b/arch/mips/alchemy/common/usb.c index d193dbea84a1..297805ade849 100644 --- a/arch/mips/alchemy/common/usb.c +++ b/arch/mips/alchemy/common/usb.c @@ -9,6 +9,7 @@ * */ +#include <linux/clk.h> #include <linux/init.h> #include <linux/io.h> #include <linux/module.h> @@ -387,10 +388,25 @@ static inline void au1200_usb_init(void) udelay(1000); } -static inline void au1000_usb_init(unsigned long rb, int reg) +static inline int au1000_usb_init(unsigned long rb, int reg) { void __iomem *base = (void __iomem *)KSEG1ADDR(rb + reg); unsigned long r = __raw_readl(base); + struct clk *c; + + /* 48MHz check. Don't init if no one can provide it */ + c = clk_get(NULL, "usbh_clk"); + if (IS_ERR(c)) + return -ENODEV; + if (clk_round_rate(c, 48000000) != 48000000) { + clk_put(c); + return -ENODEV; + } + if (clk_set_rate(c, 48000000)) { + clk_put(c); + return -ENODEV; + } + clk_put(c); #if defined(__BIG_ENDIAN) r |= USBHEN_BE; @@ -400,6 +416,8 @@ static inline void au1000_usb_init(unsigned long rb, int reg) __raw_writel(r, base); wmb(); udelay(1000); + + return 0; } @@ -407,8 +425,15 @@ static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) { void __iomem *base = (void __iomem *)KSEG1ADDR(rb); unsigned long r = __raw_readl(base + creg); + struct clk *c = clk_get(NULL, "usbh_clk"); + + if (IS_ERR(c)) + return; if (enable) { + if (clk_prepare_enable(c)) + goto out; + __raw_writel(r | USBHEN_CE, base + creg); wmb(); udelay(1000); @@ -423,7 +448,10 @@ static inline void __au1xx0_ohci_control(int enable, unsigned long rb, int creg) } else { __raw_writel(r & ~(USBHEN_CE | USBHEN_E), base + creg); wmb(); + clk_disable_unprepare(c); } +out: + clk_put(c); } static inline int au1000_usb_control(int block, int enable, unsigned long rb, @@ -457,11 +485,11 @@ int alchemy_usb_control(int block, int enable) case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1100: ret = au1000_usb_control(block, enable, - AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); + AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); break; case ALCHEMY_CPU_AU1550: ret = au1000_usb_control(block, enable, - AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); + AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); break; case ALCHEMY_CPU_AU1200: ret = au1200_usb_control(block, enable); @@ -569,14 +597,18 @@ static struct syscore_ops alchemy_usb_pm_ops = { static int __init alchemy_usb_init(void) { + int ret = 0; + switch (alchemy_get_cputype()) { case ALCHEMY_CPU_AU1000: case ALCHEMY_CPU_AU1500: case ALCHEMY_CPU_AU1100: - au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, AU1000_OHCICFG); + ret = au1000_usb_init(AU1000_USB_OHCI_PHYS_ADDR, + AU1000_OHCICFG); break; case ALCHEMY_CPU_AU1550: - au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, AU1550_OHCICFG); + ret = au1000_usb_init(AU1550_USB_OHCI_PHYS_ADDR, + AU1550_OHCICFG); break; case ALCHEMY_CPU_AU1200: au1200_usb_init(); @@ -586,8 +618,9 @@ static int __init alchemy_usb_init(void) break; } - register_syscore_ops(&alchemy_usb_pm_ops); + if (!ret) + register_syscore_ops(&alchemy_usb_pm_ops); - return 0; + return ret; } arch_initcall(alchemy_usb_init); diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 92dd929d4057..001102e197f1 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/gpio.h> #include <linux/init.h> @@ -496,6 +497,7 @@ int __init db1000_dev_setup(void) int board = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); int c0, c1, d0, d1, s0, s1, flashsize = 32, twosocks = 1; unsigned long pfc; + struct clk *c, *p; if (board == BCSR_WHOAMI_DB1500) { c0 = AU1500_GPIO2_INT; @@ -518,14 +520,25 @@ int __init db1000_dev_setup(void) gpio_direction_input(20); /* sd1 cd# */ /* spi_gpio on SSI0 pins */ - pfc = __raw_readl((void __iomem *)SYS_PINFUNC); + pfc = alchemy_rdsys(AU1000_SYS_PINFUNC); pfc |= (1 << 0); /* SSI0 pins as GPIOs */ - __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); - wmb(); + alchemy_wrsys(pfc, AU1000_SYS_PINFUNC); spi_register_board_info(db1100_spi_info, ARRAY_SIZE(db1100_spi_info)); + /* link LCD clock to AUXPLL */ + p = clk_get(NULL, "auxpll_clk"); + c = clk_get(NULL, "lcd_intclk"); + if (!IS_ERR(c) && !IS_ERR(p)) { + clk_set_parent(c, p); + clk_set_rate(c, clk_get_rate(p)); + } + if (!IS_ERR(c)) + clk_put(c); + if (!IS_ERR(p)) + clk_put(p); + platform_add_devices(db1100_devs, ARRAY_SIZE(db1100_devs)); platform_device_register(&db1100_spi_dev); } else if (board == BCSR_WHOAMI_DB1000) { diff --git a/arch/mips/alchemy/devboards/db1200.c b/arch/mips/alchemy/devboards/db1200.c index 9e46667f2597..776188908dfc 100644 --- a/arch/mips/alchemy/devboards/db1200.c +++ b/arch/mips/alchemy/devboards/db1200.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/gpio.h> #include <linux/i2c.h> @@ -129,7 +130,6 @@ static int __init db1200_detect_board(void) int __init db1200_board_setup(void) { - unsigned long freq0, clksrc, div, pfc; unsigned short whoami; if (db1200_detect_board()) @@ -149,34 +149,6 @@ int __init db1200_board_setup(void) " Board-ID %d Daughtercard ID %d\n", get_system_type(), (whoami >> 4) & 0xf, (whoami >> 8) & 0xf, whoami & 0xf); - /* SMBus/SPI on PSC0, Audio on PSC1 */ - pfc = __raw_readl((void __iomem *)SYS_PINFUNC); - pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); - pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); - pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ - __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); - wmb(); - - /* Clock configurations: PSC0: ~50MHz via Clkgen0, derived from - * CPU clock; all other clock generators off/unused. - */ - div = (get_au1x00_speed() + 25000000) / 50000000; - if (div & 1) - div++; - div = ((div >> 1) - 1) & 0xff; - - freq0 = div << SYS_FC_FRDIV0_BIT; - __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); - wmb(); - freq0 |= SYS_FC_FE0; /* enable F0 */ - __raw_writel(freq0, (void __iomem *)SYS_FREQCTRL0); - wmb(); - - /* psc0_intclk comes 1:1 from F0 */ - clksrc = SYS_CS_MUX_FQ0 << SYS_CS_ME0_BIT; - __raw_writel(clksrc, (void __iomem *)SYS_CLKSRC); - wmb(); - return 0; } @@ -250,7 +222,7 @@ static void au1200_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, static int au1200_nand_device_ready(struct mtd_info *mtd) { - return __raw_readl((void __iomem *)MEM_STSTAT) & 1; + return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1; } static struct mtd_partition db1200_nand_parts[] = { @@ -847,6 +819,7 @@ int __init db1200_dev_setup(void) unsigned long pfc; unsigned short sw; int swapped, bid; + struct clk *c; bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)); if ((bid == BCSR_WHOAMI_PB1200_DDR1) || @@ -859,6 +832,24 @@ int __init db1200_dev_setup(void) irq_set_irq_type(AU1200_GPIO7_INT, IRQ_TYPE_LEVEL_LOW); bcsr_init_irq(DB1200_INT_BEGIN, DB1200_INT_END, AU1200_GPIO7_INT); + /* SMBus/SPI on PSC0, Audio on PSC1 */ + pfc = alchemy_rdsys(AU1000_SYS_PINFUNC); + pfc &= ~(SYS_PINFUNC_P0A | SYS_PINFUNC_P0B); + pfc &= ~(SYS_PINFUNC_P1A | SYS_PINFUNC_P1B | SYS_PINFUNC_FS3); + pfc |= SYS_PINFUNC_P1C; /* SPI is configured later */ + alchemy_wrsys(pfc, AU1000_SYS_PINFUNC); + + /* get 50MHz for I2C driver on PSC0 */ + c = clk_get(NULL, "psc0_intclk"); + if (!IS_ERR(c)) { + pfc = clk_round_rate(c, 50000000); + if ((pfc < 1) || (abs(50000000 - pfc) > 2500000)) + pr_warn("DB1200: cant get I2C close to 50MHz\n"); + else + clk_set_rate(c, pfc); + clk_put(c); + } + /* insert/eject pairs: one of both is always screaming. To avoid * issues they must not be automatically enabled when initially * requested. @@ -886,7 +877,7 @@ int __init db1200_dev_setup(void) * As a result, in SPI mode, OTG simply won't work (PSC0 uses * it as an input pin which is pulled high on the boards). */ - pfc = __raw_readl((void __iomem *)SYS_PINFUNC) & ~SYS_PINFUNC_P0A; + pfc = alchemy_rdsys(AU1000_SYS_PINFUNC) & ~SYS_PINFUNC_P0A; /* switch off OTG VBUS supply */ gpio_request(215, "otg-vbus"); @@ -912,8 +903,7 @@ int __init db1200_dev_setup(void) printk(KERN_INFO " S6.8 ON : PSC0 mode SPI\n"); printk(KERN_INFO " OTG port VBUS supply disabled\n"); } - __raw_writel(pfc, (void __iomem *)SYS_PINFUNC); - wmb(); + alchemy_wrsys(pfc, AU1000_SYS_PINFUNC); /* Audio: DIP7 selects I2S(0)/AC97(1), but need I2C for I2S! * so: DIP7=1 || DIP8=0 => AC97, DIP7=0 && DIP8=1 => I2S @@ -932,6 +922,11 @@ int __init db1200_dev_setup(void) } /* Audio PSC clock is supplied externally. (FIXME: platdata!!) */ + c = clk_get(NULL, "psc1_intclk"); + if (!IS_ERR(c)) { + clk_prepare_enable(c); + clk_put(c); + } __raw_writel(PSC_SEL_CLK_SERCLK, (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); wmb(); diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index 1aed6be4de10..ef93ee3f6a2c 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -4,6 +4,7 @@ * (c) 2009 Manuel Lauss <manuel.lauss@googlemail.com> */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/gpio.h> #include <linux/gpio_keys.h> @@ -169,7 +170,7 @@ static void au1300_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, static int au1300_nand_device_ready(struct mtd_info *mtd) { - return __raw_readl((void __iomem *)MEM_STSTAT) & 1; + return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1; } static struct mtd_partition db1300_nand_parts[] = { @@ -731,6 +732,7 @@ static struct platform_device *db1300_dev[] __initdata = { int __init db1300_dev_setup(void) { int swapped, cpldirq; + struct clk *c; /* setup CPLD IRQ muxer */ cpldirq = au1300_gpio_to_irq(AU1300_PIN_EXTCLK1); @@ -761,6 +763,11 @@ int __init db1300_dev_setup(void) (void __iomem *)KSEG1ADDR(AU1300_PSC2_PHYS_ADDR) + PSC_SEL_OFFSET); wmb(); /* I2C uses internal 48MHz EXTCLK1 */ + c = clk_get(NULL, "psc3_intclk"); + if (!IS_ERR(c)) { + clk_prepare_enable(c); + clk_put(c); + } __raw_writel(PSC_SEL_CLK_INTCLK, (void __iomem *)KSEG1ADDR(AU1300_PSC3_PHYS_ADDR) + PSC_SEL_OFFSET); wmb(); diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index bbd8d9884702..7e89936f763e 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -4,6 +4,7 @@ * (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com> */ +#include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/gpio.h> #include <linux/i2c.h> @@ -31,16 +32,16 @@ static void __init db1550_hw_setup(void) { void __iomem *base; + unsigned long v; /* complete SPI setup: link psc0_intclk to a 48MHz source, * and assign GPIO16 to PSC0_SYNC1 (SPI cs# line) as well as PSC1_SYNC * for AC97 on PB1550. */ - base = (void __iomem *)SYS_CLKSRC; - __raw_writel(__raw_readl(base) | 0x000001e0, base); - base = (void __iomem *)SYS_PINFUNC; - __raw_writel(__raw_readl(base) | 1 | SYS_PF_PSC1_S1, base); - wmb(); + v = alchemy_rdsys(AU1000_SYS_CLKSRC); + alchemy_wrsys(v | 0x000001e0, AU1000_SYS_CLKSRC); + v = alchemy_rdsys(AU1000_SYS_PINFUNC); + alchemy_wrsys(v | 1 | SYS_PF_PSC1_S1, AU1000_SYS_PINFUNC); /* reset the AC97 codec now, the reset time in the psc-ac97 driver * is apparently too short although it's ridiculous as it is. @@ -151,7 +152,7 @@ static void au1550_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, static int au1550_nand_device_ready(struct mtd_info *mtd) { - return __raw_readl((void __iomem *)MEM_STSTAT) & 1; + return alchemy_rdsmem(AU1000_MEM_STSTAT) & 1; } static struct mtd_partition db1550_nand_parts[] = { @@ -217,7 +218,7 @@ static struct platform_device pb1550_nand_dev = { static void __init pb1550_nand_setup(void) { - int boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | + int boot_swapboot = (alchemy_rdsmem(AU1000_MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1); gpio_direction_input(206); /* de-assert NAND CS# */ @@ -574,6 +575,7 @@ static void __init pb1550_devices(void) int __init db1550_dev_setup(void) { int swapped, id; + struct clk *c; id = (BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI)) != BCSR_WHOAMI_DB1550); @@ -582,6 +584,17 @@ int __init db1550_dev_setup(void) spi_register_board_info(db1550_spi_devs, ARRAY_SIZE(db1550_i2c_devs)); + c = clk_get(NULL, "psc0_intclk"); + if (!IS_ERR(c)) { + clk_prepare_enable(c); + clk_put(c); + } + c = clk_get(NULL, "psc2_intclk"); + if (!IS_ERR(c)) { + clk_prepare_enable(c); + clk_put(c); + } + /* Audio PSC clock is supplied by codecs (PSC1, 3) FIXME: platdata!! */ __raw_writel(PSC_SEL_CLK_SERCLK, (void __iomem *)KSEG1ADDR(AU1550_PSC1_PHYS_ADDR) + PSC_SEL_OFFSET); diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index 61e90fe9eab1..bfeb8f3c0be6 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c @@ -45,23 +45,20 @@ static int db1x_pm_enter(suspend_state_t state) alchemy_gpio1_input_enable(); /* clear and setup wake cause and source */ - au_writel(0, SYS_WAKEMSK); - au_sync(); - au_writel(0, SYS_WAKESRC); - au_sync(); + alchemy_wrsys(0, AU1000_SYS_WAKEMSK); + alchemy_wrsys(0, AU1000_SYS_WAKESRC); - au_writel(db1x_pm_wakemsk, SYS_WAKEMSK); - au_sync(); + alchemy_wrsys(db1x_pm_wakemsk, AU1000_SYS_WAKEMSK); /* setup 1Hz-timer-based wakeup: wait for reg access */ - while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) + while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20) asm volatile ("nop"); - au_writel(au_readl(SYS_TOYREAD) + db1x_pm_sleep_secs, SYS_TOYMATCH2); - au_sync(); + alchemy_wrsys(alchemy_rdsys(AU1000_SYS_TOYREAD) + db1x_pm_sleep_secs, + AU1000_SYS_TOYMATCH2); /* wait for value to really hit the register */ - while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20) + while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20) asm volatile ("nop"); /* ...and now the sandman can come! */ @@ -102,12 +99,10 @@ static void db1x_pm_end(void) /* read and store wakeup source, the clear the register. To * be able to clear it, WAKEMSK must be cleared first. */ - db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC); - - au_writel(0, SYS_WAKEMSK); - au_writel(0, SYS_WAKESRC); - au_sync(); + db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC); + alchemy_wrsys(0, AU1000_SYS_WAKEMSK); + alchemy_wrsys(0, AU1000_SYS_WAKESRC); } static const struct platform_suspend_ops db1x_pm_ops = { @@ -242,17 +237,13 @@ static int __init pm_init(void) * for confirmation since there's plenty of time from here to * the next suspend cycle. */ - if (au_readl(SYS_TOYTRIM) != 32767) { - au_writel(32767, SYS_TOYTRIM); - au_sync(); - } + if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767) + alchemy_wrsys(32767, AU1000_SYS_TOYTRIM); - db1x_pm_last_wakesrc = au_readl(SYS_WAKESRC); + db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC); - au_writel(0, SYS_WAKESRC); - au_sync(); - au_writel(0, SYS_WAKEMSK); - au_sync(); + alchemy_wrsys(0, AU1000_SYS_WAKESRC); + alchemy_wrsys(0, AU1000_SYS_WAKEMSK); suspend_set_ops(&db1x_pm_ops); |