Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 780019dd authored by Florian Fainelli's avatar Florian Fainelli Committed by Ralf Baechle
Browse files

MIPS: AR7: Implement clock API



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: default avatarFlorian Fainelli <florian@openwrt.org>
Acked-by: default avatarWim 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: default avatarRalf Baechle <ralf@linux-mips.org>
parent 5f3c9098
Loading
Loading
Loading
Loading
+80 −29
Original line number Diff line number Diff line
/*
 * 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
@@ -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>
@@ -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)
@@ -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;
	}

@@ -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;
@@ -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;
	}

@@ -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);
@@ -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) {
@@ -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()) {
@@ -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;
}
+8 −2
Original line number Diff line number Diff line
@@ -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>
@@ -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);
@@ -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);
+11 −1
Original line number Diff line number Diff line
@@ -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;
}
+3 −20
Original line number Diff line number Diff line
@@ -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)
{
+9 −1
Original line number Diff line number Diff line
@@ -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>

@@ -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;
}

Loading