Skip to content

Commit

Permalink
MIPS: AR7: Implement clock API
Browse files Browse the repository at this point in the history
This patch makes the ar7 clock code implement the Linux clk API. Drivers
using the various clocks available in the SoC are updated accordingly.

Signed-off-by: Florian Fainelli <florian@openwrt.org>
Acked-by: Wim Van Sebroeck <wim@iguana.be>
To: linux-mips@linux-mips.org
Cc: Wim Van Sebroeck <wim@iguana.be>
Cc: netdev@vger.kernel.org
Cc: David Miller <davem@davemloft.net>
Patchwork: http://patchwork.linux-mips.org/patch/881/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Florian Fainelli authored and Ralf Baechle committed Feb 27, 2010
1 parent 5f3c909 commit 780019d
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 56 deletions.
109 changes: 80 additions & 29 deletions arch/mips/ar7/clock.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2007 Eugene Konev <ejka@openwrt.org>
* Copyright (C) 2009 Florian Fainelli <florian@openwrt.org>
*
* 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
Expand All @@ -24,6 +25,8 @@
#include <linux/delay.h>
#include <linux/gcd.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>

#include <asm/addrspace.h>
#include <asm/mach-ar7/ar7.h>
Expand Down Expand Up @@ -94,12 +97,16 @@ struct tnetd7200_clocks {
struct tnetd7200_clock usb;
};

int ar7_cpu_clock = 150000000;
EXPORT_SYMBOL(ar7_cpu_clock);
int ar7_bus_clock = 125000000;
EXPORT_SYMBOL(ar7_bus_clock);
int ar7_dsp_clock;
EXPORT_SYMBOL(ar7_dsp_clock);
static struct clk bus_clk = {
.rate = 125000000,
};

static struct clk cpu_clk = {
.rate = 150000000,
};

static struct clk dsp_clk;
static struct clk vbus_clk;

static void approximate(int base, int target, int *prediv,
int *postdiv, int *mul)
Expand Down Expand Up @@ -185,7 +192,7 @@ static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
base_clock = AR7_XTAL_CLOCK;
break;
case BOOT_PLL_SOURCE_CPU:
base_clock = ar7_cpu_clock;
base_clock = cpu_clk.rate;
break;
}

Expand All @@ -212,11 +219,11 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
u32 *bootcr, u32 frequency)
{
int prediv, postdiv, mul;
int base_clock = ar7_bus_clock;
int base_clock = bus_clk.rate;

switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
case BOOT_PLL_SOURCE_BUS:
base_clock = ar7_bus_clock;
base_clock = bus_clk.rate;
break;
case BOOT_PLL_SOURCE_REF:
base_clock = AR7_REF_CLOCK;
Expand All @@ -225,7 +232,7 @@ static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
base_clock = AR7_XTAL_CLOCK;
break;
case BOOT_PLL_SOURCE_CPU:
base_clock = ar7_cpu_clock;
base_clock = cpu_clk.rate;
break;
}

Expand All @@ -247,18 +254,18 @@ static void __init tnetd7300_init_clocks(void)
ioremap_nocache(UR8_REGS_CLOCKS,
sizeof(struct tnetd7300_clocks));

ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
bus_clk.rate = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
&clocks->bus, bootcr, AR7_AFE_CLOCK);

if (*bootcr & BOOT_PLL_ASYNC_MODE)
ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
cpu_clk.rate = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
&clocks->cpu, bootcr, AR7_AFE_CLOCK);
else
ar7_cpu_clock = ar7_bus_clock;
cpu_clk.rate = bus_clk.rate;

if (ar7_dsp_clock == 250000000)
if (dsp_clk.rate == 250000000)
tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
bootcr, ar7_dsp_clock);
bootcr, dsp_clk.rate);

iounmap(clocks);
iounmap(bootcr);
Expand Down Expand Up @@ -343,20 +350,20 @@ static void __init tnetd7200_init_clocks(void)
printk(KERN_INFO "Clocks: Setting DSP clock\n");
calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
&dsp_prediv, &dsp_postdiv, &dsp_mul);
ar7_bus_clock =
bus_clk.rate =
((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
tnetd7200_set_clock(dsp_base, &clocks->dsp,
dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
ar7_bus_clock);
bus_clk.rate);

printk(KERN_INFO "Clocks: Setting CPU clock\n");
calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
&cpu_postdiv, &cpu_mul);
ar7_cpu_clock =
cpu_clk.rate =
((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
tnetd7200_set_clock(cpu_base, &clocks->cpu,
cpu_prediv, cpu_postdiv, -1, cpu_mul,
ar7_cpu_clock);
cpu_clk.rate);

} else
if (*bootcr & BOOT_PLL_2TO1_MODE) {
Expand All @@ -365,48 +372,90 @@ static void __init tnetd7200_init_clocks(void)
printk(KERN_INFO "Clocks: Setting CPU clock\n");
calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
&cpu_postdiv, &cpu_mul);
ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
cpu_clk.rate = ((cpu_base / cpu_prediv) * cpu_mul)
/ cpu_postdiv;
tnetd7200_set_clock(cpu_base, &clocks->cpu,
cpu_prediv, cpu_postdiv, -1, cpu_mul,
ar7_cpu_clock);
cpu_clk.rate);

printk(KERN_INFO "Clocks: Setting DSP clock\n");
calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
&dsp_postdiv, &dsp_mul);
ar7_bus_clock = ar7_cpu_clock / 2;
bus_clk.rate = cpu_clk.rate / 2;
tnetd7200_set_clock(dsp_base, &clocks->dsp,
dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
dsp_mul * 2, ar7_bus_clock);
dsp_mul * 2, bus_clk.rate);
} else {
printk(KERN_INFO "Clocks: Sync 1:1 mode\n");

printk(KERN_INFO "Clocks: Setting DSP clock\n");
calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
&dsp_postdiv, &dsp_mul);
ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
bus_clk.rate = ((dsp_base / dsp_prediv) * dsp_mul)
/ dsp_postdiv;
tnetd7200_set_clock(dsp_base, &clocks->dsp,
dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
dsp_mul * 2, ar7_bus_clock);
dsp_mul * 2, bus_clk.rate);

ar7_cpu_clock = ar7_bus_clock;
cpu_clk.rate = bus_clk.rate;
}

printk(KERN_INFO "Clocks: Setting USB clock\n");
usb_base = ar7_bus_clock;
usb_base = bus_clk.rate;
calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
&usb_postdiv, &usb_mul);
tnetd7200_set_clock(usb_base, &clocks->usb,
usb_prediv, usb_postdiv, -1, usb_mul,
TNETD7200_DEF_USB_CLK);

ar7_dsp_clock = ar7_cpu_clock;
dsp_clk.rate = cpu_clk.rate;

iounmap(clocks);
iounmap(bootcr);
}

/*
* Linux clock API
*/
int clk_enable(struct clk *clk)
{
return 0;
}
EXPORT_SYMBOL(clk_enable);

void clk_disable(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_disable);

unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);

struct clk *clk_get(struct device *dev, const char *id)
{
if (!strcmp(id, "bus"))
return &bus_clk;
/* cpmac and vbus share the same rate */
if (!strcmp(id, "cpmac"))
return &vbus_clk;
if (!strcmp(id, "cpu"))
return &cpu_clk;
if (!strcmp(id, "dsp"));
return &dsp_clk;
if (!strcmp(id, "vbus"))
return &vbus_clk;
return ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get);

void clk_put(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_put);

int __init ar7_init_clocks(void)
{
switch (ar7_chip_id()) {
Expand All @@ -415,12 +464,14 @@ int __init ar7_init_clocks(void)
tnetd7200_init_clocks();
break;
case AR7_CHIP_7300:
ar7_dsp_clock = tnetd7300_dsp_clock();
dsp_clk.rate = tnetd7300_dsp_clock();
tnetd7300_init_clocks();
break;
default:
break;
}
/* adjust vbus clock rate */
vbus_clk.rate = bus_clk.rate / 2;

return 0;
}
Expand Down
10 changes: 8 additions & 2 deletions arch/mips/ar7/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/phy.h>
#include <linux/phy_fixed.h>
#include <linux/gpio.h>
#include <linux/clk.h>

#include <asm/addrspace.h>
#include <asm/mach-ar7/ar7.h>
Expand Down Expand Up @@ -507,13 +508,18 @@ static int __init ar7_register_devices(void)
u32 *bootcr, val;
#ifdef CONFIG_SERIAL_8250
static struct uart_port uart_port[2] __initdata;
struct clk *bus_clk;

memset(uart_port, 0, sizeof(struct uart_port) * 2);

bus_clk = clk_get(NULL, "bus");
if (IS_ERR(bus_clk))
panic("unable to get bus clk\n");

uart_port[0].type = PORT_16550A;
uart_port[0].line = 0;
uart_port[0].irq = AR7_IRQ_UART0;
uart_port[0].uartclk = ar7_bus_freq() / 2;
uart_port[0].uartclk = clk_get_rate(bus_clk) / 2;
uart_port[0].iotype = UPIO_MEM32;
uart_port[0].mapbase = AR7_REGS_UART0;
uart_port[0].membase = ioremap(uart_port[0].mapbase, 256);
Expand All @@ -528,7 +534,7 @@ static int __init ar7_register_devices(void)
uart_port[1].type = PORT_16550A;
uart_port[1].line = 1;
uart_port[1].irq = AR7_IRQ_UART1;
uart_port[1].uartclk = ar7_bus_freq() / 2;
uart_port[1].uartclk = clk_get_rate(bus_clk) / 2;
uart_port[1].iotype = UPIO_MEM32;
uart_port[1].mapbase = UR8_REGS_UART1;
uart_port[1].membase = ioremap(uart_port[1].mapbase, 256);
Expand Down
12 changes: 11 additions & 1 deletion arch/mips/ar7/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,21 @@

#include <linux/init.h>
#include <linux/time.h>
#include <linux/err.h>
#include <linux/clk.h>

#include <asm/time.h>
#include <asm/mach-ar7/ar7.h>

void __init plat_time_init(void)
{
mips_hpt_frequency = ar7_cpu_freq() / 2;
struct clk *cpu_clk;

cpu_clk = clk_get(NULL, "cpu");
if (IS_ERR(cpu_clk)) {
printk(KERN_ERR "unable to get cpu clock\n");
return;
}

mips_hpt_frequency = clk_get_rate(cpu_clk) / 2;
}
23 changes: 3 additions & 20 deletions arch/mips/include/asm/mach-ar7/ar7.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,9 @@ static inline u8 ar7_chip_rev(void)
return (readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x14)) >> 16) & 0xff;
}

static inline int ar7_cpu_freq(void)
{
return ar7_cpu_clock;
}

static inline int ar7_bus_freq(void)
{
return ar7_bus_clock;
}

static inline int ar7_vbus_freq(void)
{
return ar7_bus_clock / 2;
}
#define ar7_cpmac_freq ar7_vbus_freq

static inline int ar7_dsp_freq(void)
{
return ar7_dsp_clock;
}
struct clk {
unsigned int rate;
};

static inline int ar7_has_high_cpmac(void)
{
Expand Down
10 changes: 9 additions & 1 deletion drivers/net/cpmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <linux/phy_fixed.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <asm/gpio.h>
#include <asm/atomic.h>

Expand Down Expand Up @@ -294,9 +295,16 @@ static int cpmac_mdio_write(struct mii_bus *bus, int phy_id,

static int cpmac_mdio_reset(struct mii_bus *bus)
{
struct clk *cpmac_clk;

cpmac_clk = clk_get(&bus->dev, "cpmac");
if (IS_ERR(cpmac_clk)) {
printk(KERN_ERR "unable to get cpmac clock\n");
return -1;
}
ar7_device_reset(AR7_RESET_BIT_MDIO);
cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE |
MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1));
MDIOC_CLKDIV(clk_get_rate(cpmac_clk) / 2200000 - 1));
return 0;
}

Expand Down
Loading

0 comments on commit 780019d

Please sign in to comment.