* [PATCH 0/3] introduce clk framework @ 2010-08-03 12:51 Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 1 reply; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:51 UTC (permalink / raw) To: barebox Hi, The following changes since commit 139ec08127825f2fdc4d0386d26f1fad9f745c2c: Merge branch 'next' (2010-08-03 09:31:38 +0200) Jean-Christophe PLAGNIOL-VILLARD (3): initcall: add postconsole_initcall clock: Introduce clock framework from Linux at91: implement clock framework arch/arm/boards/at91sam9260ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/init.c | 3 - arch/arm/boards/mmccpu/config.h | 2 +- arch/arm/boards/mmccpu/init.c | 3 - arch/arm/boards/pm9263/config.h | 2 +- arch/arm/boards/pm9263/init.c | 3 - arch/arm/mach-at91/Makefile | 2 +- arch/arm/mach-at91/at91sam9260.c | 207 ++++++++ arch/arm/mach-at91/at91sam9260_devices.c | 18 +- arch/arm/mach-at91/at91sam9263.c | 217 +++++++++ arch/arm/mach-at91/at91sam9263_devices.c | 13 +- arch/arm/mach-at91/clock.c | 672 +++++++++++++++++++++++++++ arch/arm/mach-at91/clock.h | 31 ++ arch/arm/mach-at91/generic.h | 14 + arch/arm/mach-at91/gpio.c | 3 + arch/arm/mach-at91/include/mach/at91_dbgu.h | 66 +++ arch/arm/mach-at91/include/mach/clk.h | 39 -- arch/arm/mach-at91/include/mach/cpu.h | 118 +++++ arch/arm/mach-at91/include/mach/gpio.h | 1 + drivers/net/macb.c | 11 +- drivers/serial/atmel.c | 32 ++- include/init.h | 1 + include/linux/clk.h | 158 +++++++ 24 files changed, 1545 insertions(+), 75 deletions(-) create mode 100644 arch/arm/mach-at91/clock.c create mode 100644 arch/arm/mach-at91/clock.h create mode 100644 arch/arm/mach-at91/generic.h create mode 100644 arch/arm/mach-at91/include/mach/at91_dbgu.h delete mode 100644 arch/arm/mach-at91/include/mach/clk.h create mode 100644 arch/arm/mach-at91/include/mach/cpu.h create mode 100644 include/linux/clk.h Best Regards, J. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/3] initcall: add postconsole_initcall 2010-08-03 12:51 [PATCH 0/3] introduce clk framework Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD 2010-08-29 16:53 ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 2 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw) To: barebox this will allow us to print information as soon as the console will be enable Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- include/init.h | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/include/init.h b/include/init.h index eb606f3..c5dea07 100644 --- a/include/init.h +++ b/include/init.h @@ -11,6 +11,7 @@ typedef int (*initcall_t)(void); #define core_initcall(fn) __define_initcall("0",fn,0) #define postcore_initcall(fn) __define_initcall("1",fn,1) #define console_initcall(fn) __define_initcall("2",fn,2) +#define postconsole_initcall(fn) __define_initcall("3",fn,3) #define coredevice_initcall(fn) __define_initcall("4",fn,4) #define fs_initcall(fn) __define_initcall("5",fn,5) #define device_initcall(fn) __define_initcall("6",fn,6) -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/3] clock: Introduce clock framework from Linux 2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD 2010-08-29 16:53 ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 1 reply; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw) To: barebox Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- include/linux/clk.h | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 158 insertions(+), 0 deletions(-) create mode 100644 include/linux/clk.h diff --git a/include/linux/clk.h b/include/linux/clk.h new file mode 100644 index 0000000..0cf86d7 --- /dev/null +++ b/include/linux/clk.h @@ -0,0 +1,158 @@ +/* + * linux/include/linux/clk.h + * + * Copyright (C) 2004 ARM Limited. + * Written by Deep Blue Solutions Limited. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __LINUX_CLK_H +#define __LINUX_CLK_H + +struct device_d; + +/* + * The base API. + */ + + +/* + * struct clk - an machine class defined object / cookie. + */ +struct clk; + +/** + * clk_get - lookup and obtain a reference to a clock producer. + * @dev: device for clock "consumer" + * @id: clock comsumer ID + * + * Returns a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev and @id to determine the clock consumer, and thereby + * the clock producer. (IOW, @id may be identical strings, but + * clk_get may return different clock producers depending on @dev.) + * + * Drivers must assume that the clock source is not enabled. + * + * clk_get should not be called from within interrupt context. + */ +struct clk *clk_get(struct device_d *dev, const char *id); + +/** + * clk_enable - inform the system when the clock source should be running. + * @clk: clock source + * + * If the clock can not be enabled/disabled, this should return success. + * + * Returns success (0) or negative errno. + */ +int clk_enable(struct clk *clk); + +/** + * clk_disable - inform the system when the clock source is no longer required. + * @clk: clock source + * + * Inform the system that a clock source is no longer required by + * a driver and may be shut down. + * + * Implementation detail: if the clock source is shared between + * multiple drivers, clk_enable() calls must be balanced by the + * same number of clk_disable() calls for the clock source to be + * disabled. + */ +void clk_disable(struct clk *clk); + +/** + * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. + * This is only valid once the clock source has been enabled. + * @clk: clock source + */ +unsigned long clk_get_rate(struct clk *clk); + +/** + * clk_put - "free" the clock source + * @clk: clock source + * + * Note: drivers must ensure that all clk_enable calls made on this + * clock source are balanced by clk_disable calls prior to calling + * this function. + * + * clk_put should not be called from within interrupt context. + */ +void clk_put(struct clk *clk); + + +/* + * The remaining APIs are optional for machine class support. + */ + + +/** + * clk_round_rate - adjust a rate to the exact rate a clock can provide + * @clk: clock source + * @rate: desired clock rate in Hz + * + * Returns rounded clock rate in Hz, or negative errno. + */ +long clk_round_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_rate - set the clock rate for a clock source + * @clk: clock source + * @rate: desired clock rate in Hz + * + * Returns success (0) or negative errno. + */ +int clk_set_rate(struct clk *clk, unsigned long rate); + +/** + * clk_set_parent - set the parent clock source for this clock + * @clk: clock source + * @parent: parent clock source + * + * Returns success (0) or negative errno. + */ +int clk_set_parent(struct clk *clk, struct clk *parent); + +/** + * clk_get_parent - get the parent clock source for this clock + * @clk: clock source + * + * Returns struct clk corresponding to parent clock source, or + * valid IS_ERR() condition containing errno. + */ +struct clk *clk_get_parent(struct clk *clk); + +/** + * clk_get_sys - get a clock based upon the device name + * @dev_id: device name + * @con_id: connection ID + * + * Returns a struct clk corresponding to the clock producer, or + * valid IS_ERR() condition containing errno. The implementation + * uses @dev_id and @con_id to determine the clock consumer, and + * thereby the clock producer. In contrast to clk_get() this function + * takes the device name instead of the device itself for identification. + * + * Drivers must assume that the clock source is not enabled. + * + * clk_get_sys should not be called from within interrupt context. + */ +struct clk *clk_get_sys(const char *dev_id, const char *con_id); + +/** + * clk_add_alias - add a new clock alias + * @alias: name for clock alias + * @alias_dev_name: device name + * @id: platform specific clock name + * @dev: device + * + * Allows using generic clock names for drivers by adding a new alias. + * Assumes clkdev, see clkdev.h for more info. + */ +int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, + struct device_d *dev); + +#endif -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/3] at91: implement clock framework 2010-08-03 12:53 ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 20:23 ` Sascha Hauer 2010-08-04 1:33 ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 2 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw) To: barebox this implementation is based on linux one it will calculate all the clock dynamically instead of statictly this will use also the new clock framework it will also print the clock status after the console init Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- arch/arm/boards/at91sam9260ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/init.c | 3 - arch/arm/boards/mmccpu/config.h | 2 +- arch/arm/boards/mmccpu/init.c | 3 - arch/arm/boards/pm9263/config.h | 2 +- arch/arm/boards/pm9263/init.c | 3 - arch/arm/mach-at91/Makefile | 2 +- arch/arm/mach-at91/at91sam9260.c | 207 ++++++++ arch/arm/mach-at91/at91sam9260_devices.c | 18 +- arch/arm/mach-at91/at91sam9263.c | 217 +++++++++ arch/arm/mach-at91/at91sam9263_devices.c | 13 +- arch/arm/mach-at91/clock.c | 672 +++++++++++++++++++++++++++ arch/arm/mach-at91/clock.h | 31 ++ arch/arm/mach-at91/generic.h | 14 + arch/arm/mach-at91/gpio.c | 3 + arch/arm/mach-at91/include/mach/at91_dbgu.h | 66 +++ arch/arm/mach-at91/include/mach/clk.h | 39 -- arch/arm/mach-at91/include/mach/cpu.h | 118 +++++ arch/arm/mach-at91/include/mach/gpio.h | 1 + drivers/net/macb.c | 11 +- drivers/serial/atmel.c | 32 ++- 22 files changed, 1386 insertions(+), 75 deletions(-) create mode 100644 arch/arm/mach-at91/clock.c create mode 100644 arch/arm/mach-at91/clock.h create mode 100644 arch/arm/mach-at91/generic.h create mode 100644 arch/arm/mach-at91/include/mach/at91_dbgu.h delete mode 100644 arch/arm/mach-at91/include/mach/clk.h create mode 100644 arch/arm/mach-at91/include/mach/cpu.h diff --git a/arch/arm/boards/at91sam9260ek/config.h b/arch/arm/boards/at91sam9260ek/config.h index afd8563..006820c 100644 --- a/arch/arm/boards/at91sam9260ek/config.h +++ b/arch/arm/boards/at91sam9260ek/config.h @@ -1,6 +1,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 /* 18.432 MHz crystal */ #endif /* __CONFIG_H */ diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h index 9cc8af2..bc33227 100644 --- a/arch/arm/boards/at91sam9263ek/config.h +++ b/arch/arm/boards/at91sam9263ek/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 100000000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 16367660 /* 16.367 MHz crystal */ #define MASTER_PLL_MUL 171 #define MASTER_PLL_DIV 14 diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c index 21803ca..61cd295 100644 --- a/arch/arm/boards/at91sam9263ek/init.c +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -108,9 +108,6 @@ static int at91sam9263ek_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); ek_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h index 1133b8f..422ac09 100644 --- a/arch/arm/boards/mmccpu/config.h +++ b/arch/arm/boards/mmccpu/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ +#define AT91_M1IN_CLOCK 18432000 /* values */ #define MASTER_PLL_MUL 54 diff --git a/arch/arm/boards/mmccpu/init.c b/arch/arm/boards/mmccpu/init.c index e010a83..9a7d930 100644 --- a/arch/arm/boards/mmccpu/init.c +++ b/arch/arm/boards/mmccpu/init.c @@ -58,9 +58,6 @@ static int mmccpu_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(128 * 1024 * 1024); at91_add_device_eth(&macb_pdata); register_device(&cfi_dev); diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h index 9a9c5cd..5252df2 100644 --- a/arch/arm/boards/pm9263/config.h +++ b/arch/arm/boards/pm9263/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 #define MASTER_PLL_DIV 6 #define MASTER_PLL_MUL 65 diff --git a/arch/arm/boards/pm9263/init.c b/arch/arm/boards/pm9263/init.c index 88b91ea..d5ed921 100644 --- a/arch/arm/boards/pm9263/init.c +++ b/arch/arm/boards/pm9263/init.c @@ -107,9 +107,6 @@ static int pm9263_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); pm_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index c848919..0f55883 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -1,4 +1,4 @@ -obj-y += clocksource.o gpio.o +obj-y += clock.o clocksource.o gpio.o obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 1a6e356..30d1a6a 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -2,22 +2,229 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "generic.h" +#include "clock.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioC_clk = { + .name = "pioC_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk adc_clk = { + .name = "adc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ADC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc_clk = { + .name = "mci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_MCI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc_clk = { + .name = "ssc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SSC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9260_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart3_clk = { + .name = "usart3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart4_clk = { + .name = "usart4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart5_clk = { + .name = "usart5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US5, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc3_clk = { + .name = "tc3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc4_clk = { + .name = "tc4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc5_clk = { + .name = "tc5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC5, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioC_clk, + &adc_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc_clk, + &udc_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc_clk, + &tc0_clk, + &tc1_clk, + &tc2_clk, + &ohci_clk, + &macb_clk, + &isi_clk, + &usart3_clk, + &usart4_clk, + &usart5_clk, + &tc3_clk, + &tc4_clk, + &tc5_clk, + // irq0 .. irq2 +}; + +/* + * The two programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; + +static void __init at91sam9260_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9260_gpio[] = { { .id = AT91SAM9260_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9260_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9260_ID_PIOC, .offset = AT91_PIOC, + .clock = &pioC_clk, } }; static int at91sam9260_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9260_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9260_gpio, 3); return 0; diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 0cfe913..398a721 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data sram_pdata = { .name = "sram0", .flags = DEVFS_RDWR, @@ -107,8 +109,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -233,37 +233,37 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9260_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9260_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9260_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; case AT91SAM9260_ID_US3: configure_usart3_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US3); + at91_clock_associate("usart3_clk", &uart3_serial_device, "usart"); register_device(&uart3_serial_device); break; case AT91SAM9260_ID_US4: configure_usart4_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US4); + at91_clock_associate("usart4_clk", &uart4_serial_device, "usart"); register_device(&uart4_serial_device); break; case AT91SAM9260_ID_US5: configure_usart5_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US5); + at91_clock_associate("usart5_clk", &uart5_serial_device, "usart"); register_device(&uart5_serial_device); break; default: diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 472b619..b0e3193 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -2,28 +2,245 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "clock.h" +#include "generic.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioCDE_clk = { + .name = "pioCDE_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOCDE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc0_clk = { + .name = "mci0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc1_clk = { + .name = "mci1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk can_clk = { + .name = "can_clk", + .pmc_mask = 1 << AT91SAM9263_ID_CAN, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ac97_clk = { + .name = "ac97_clk", + .pmc_mask = 1 << AT91SAM9263_ID_AC97C, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tcb_clk = { + .name = "tcb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TCB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pwm_clk = { + .name = "pwm_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PWMC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk dma_clk = { + .name = "dma_clk", + .pmc_mask = 1 << AT91SAM9263_ID_DMA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twodge_clk = { + .name = "2dge_clk", + .pmc_mask = 1 << AT91SAM9263_ID_2DGE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk lcdc_clk = { + .name = "lcdc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_LCDC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioCDE_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc0_clk, + &mmc1_clk, + &can_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc0_clk, + &ssc1_clk, + &ac97_clk, + &tcb_clk, + &pwm_clk, + &macb_clk, + &twodge_clk, + &udc_clk, + &isi_clk, + &lcdc_clk, + &dma_clk, + &ohci_clk, + // irq0 .. irq1 +}; + +/* + * The four programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 3, +}; + +static void __init at91sam9263_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); + clk_register(&pck2); + clk_register(&pck3); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9263_gpio[] = { { .id = AT91SAM9263_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9263_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOC, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOD, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOE, + .clock = &pioCDE_clk, } }; static int at91sam9263_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9263_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9263_gpio, 5); return 0; diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 50a6348..7ebc32c 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data ram_pdata = { .name = "ram0", .flags = DEVFS_RDWR, @@ -106,9 +108,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_PIOA | - 1 << AT91SAM9263_ID_PIOCDE); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -184,22 +183,22 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9263_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9263_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9263_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; default: diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c new file mode 100644 index 0000000..1912e5a --- /dev/null +++ b/arch/arm/mach-at91/clock.c @@ -0,0 +1,672 @@ +/* + * linux/arch/arm/mach-at91/clock.c + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * + * 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. + */ + +#include <common.h> +#include <linux/list.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <init.h> + +#include <mach/hardware.h> +#include <mach/io.h> +#include <mach/at91_pmc.h> +#include <mach/cpu.h> + +#include "clock.h" +#include "generic.h" + +/* + * There's a lot more which can be done with clocks, including cpufreq + * integration, slow clock mode support (for system suspend), letting + * PLLB be used at other rates (on boards that don't need USB), etc. + */ + +#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY) +#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE) +#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL) +#define clk_is_sys(x) ((x)->type & CLK_TYPE_SYSTEM) + + +/* + * Chips have some kind of clocks : group them by functionality + */ +#define cpu_has_utmi() ( cpu_is_at91cap9() \ + || cpu_is_at91sam9rl()) + +#define cpu_has_800M_plla() (cpu_is_at91sam9g20()) + +#define cpu_has_pllb() (!cpu_is_at91sam9rl()) + +#define cpu_has_upll() (0) + +/* USB host HS & FS */ +#define cpu_has_uhp() (!cpu_is_at91sam9rl()) + +/* USB device FS only */ +#define cpu_has_udpfs() (!cpu_is_at91sam9rl()) + + +static LIST_HEAD(clocks); + +static u32 at91_pllb_usb_init; + +/* + * Four primary clock sources: two crystal oscillators (32K, main), and + * two PLLs. PLLA usually runs the master clock; and PLLB must run at + * 48 MHz (unless no USB function clocks are needed). The main clock and + * both PLLs are turned off to run in "slow clock mode" (system suspend). + */ +static struct clk clk32k = { + .name = "clk32k", + .rate_hz = AT91_SLOW_CLOCK, + .users = 1, /* always on */ + .id = 0, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk main_clk = { + .name = "main", + .pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */ + .id = 1, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk plla = { + .name = "plla", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */ + .id = 2, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pllb_mode(struct clk *clk, int is_on) +{ + u32 value; + + if (is_on) { + is_on = AT91_PMC_LOCKB; + value = at91_pllb_usb_init; + } else + value = 0; + + // REVISIT: Add work-around for AT91RM9200 Errata #26 ? + at91_sys_write(AT91_CKGR_PLLBR, value); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on); +} + +static struct clk pllb = { + .name = "pllb", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */ + .mode = pllb_mode, + .id = 3, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pmc_sys_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_SCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); +} + +static void pmc_uckr_mode(struct clk *clk, int is_on) +{ + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (is_on) { + is_on = AT91_PMC_LOCKU; + at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); + } else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask)); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on); +} + +/* USB function clocks (PLLB must be 48 MHz) */ +static struct clk udpck = { + .name = "udpck", + .parent = &pllb, + .mode = pmc_sys_mode, +}; +static struct clk utmi_clk = { + .name = "utmi_clk", + .parent = &main_clk, + .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */ + .mode = pmc_uckr_mode, + .type = CLK_TYPE_PLL, +}; +static struct clk uhpck = { + .name = "uhpck", + /*.parent = ... we choose parent at runtime */ + .mode = pmc_sys_mode, +}; + + +/* + * The master clock is divided from the CPU clock (by 1-4). It's used for + * memory, interfaces to on-chip peripherals, the AIC, and sometimes more + * (e.g baud rate generation). It's sourced from one of the primary clocks. + */ +static struct clk mck = { + .name = "mck", + .pmc_mask = AT91_PMC_MCKRDY, /* in PMC_SR */ +}; + +static void pmc_periph_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_PCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask); +} + +static struct clk *at91_css_to_clk(unsigned long css) +{ + switch (css) { + case AT91_PMC_CSS_SLOW: + return &clk32k; + case AT91_PMC_CSS_MAIN: + return &main_clk; + case AT91_PMC_CSS_PLLA: + return &plla; + case AT91_PMC_CSS_PLLB: + if (cpu_has_upll()) + /* CSS_PLLB == CSS_UPLL */ + return &utmi_clk; + else if (cpu_has_pllb()) + return &pllb; + } + + return NULL; +} + +/* + * Associate a particular clock with a function (eg, "uart") and device. + * The drivers can then request the same 'function' with several different + * devices and not care about which clock name to use. + */ +void at91_clock_associate(const char *id, struct device_d *dev, const char *func) +{ + struct clk *clk = clk_get(NULL, id); + + if (!dev || !clk || !IS_ERR(clk_get(dev, func))) + return; + + clk->function = func; + clk->dev = dev; +} + +/* clocks cannot be de-registered no refcounting necessary */ +struct clk *clk_get(struct device_d *dev, const char *id) +{ + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (strcmp(id, clk->name) == 0) + return clk; + if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0) + return clk; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + if (clk->users++ == 0 && clk->mode) + clk->mode(clk, 1); +} + +int clk_enable(struct clk *clk) +{ + __clk_enable(clk); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +static void __clk_disable(struct clk *clk) +{ + BUG_ON(clk->users == 0); + if (--clk->users == 0 && clk->mode) + clk->mode(clk, 0); + if (clk->parent) + __clk_disable(clk->parent); +} + +void clk_disable(struct clk *clk) +{ + __clk_disable(clk); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + for (;;) { + rate = clk->rate_hz; + if (rate || !clk->parent) + break; + clk = clk->parent; + } + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +/*------------------------------------------------------------------------*/ + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + +/* + * For now, only the programmable clocks support reparenting (MCK could + * do this too, with care) or rate changing (the PLLs could do this too, + * ditto MCK but that's more for cpufreq). Drivers may reparent to get + * a better rate match; we don't. + */ + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk_is_programmable(clk)) + return -EINVAL; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) + break; + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk_is_programmable(clk)) + return -EINVAL; + if (clk->users) + return -EBUSY; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) { + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + pckr &= AT91_PMC_CSS; /* clock selection */ + pckr |= prescale << 2; + at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); + clk->rate_hz = actual; + break; + } + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + + if (clk->users) + return -EBUSY; + if (!clk_is_primary(parent) || !clk_is_programmable(clk)) + return -EINVAL; + + clk->rate_hz = parent->rate_hz; + clk->parent = parent; + at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id); + + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +/* establish PCK0..PCKN parentage and rate */ +static void init_programmable_clock(struct clk *clk) +{ + struct clk *parent; + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + parent = at91_css_to_clk(pckr & AT91_PMC_CSS); + clk->parent = parent; + clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2)); +} + +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + +/*------------------------------------------------------------------------*/ + +/* Register a new clock */ +int clk_register(struct clk *clk) +{ + if (clk_is_peripheral(clk)) { + clk->parent = &mck; + clk->mode = pmc_periph_mode; + list_add_tail(&clk->node, &clocks); + } + else if (clk_is_sys(clk)) { + clk->parent = &mck; + clk->mode = pmc_sys_mode; + + list_add_tail(&clk->node, &clocks); + } +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + else if (clk_is_programmable(clk)) { + clk->mode = pmc_sys_mode; + init_programmable_clock(clk); + list_add_tail(&clk->node, &clocks); + } +#endif + + return 0; +} + + +/*------------------------------------------------------------------------*/ + +static u32 at91_pll_rate(struct clk *pll, u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + + return freq; +} + +static u32 at91_usb_rate(struct clk *pll, u32 freq, u32 reg) +{ + if (pll == &pllb && (reg & AT91_PMC_USB96M)) + return freq / 2; + else + return freq; +} + +static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + * Warning: some newer products need 2MHz min. + */ + input = main_freq / i; + if (cpu_is_at91sam9g20() && input < 2000000) + continue; + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; + if (cpu_is_at91sam9g20() && mul > 63) + continue; + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} + +static struct clk *const standard_pmc_clocks[] = { + /* four primary clocks */ + &clk32k, + &main_clk, + &plla, + + /* MCK */ + &mck +}; + +/* PLLB generated USB full speed clock init */ +static void at91_pllb_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + uhpck.parent = &pllb; + + at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M; + pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); + if (cpu_is_at91rm9200()) { + uhpck.pmc_mask = AT91RM9200_PMC_UHP; + udpck.pmc_mask = AT91RM9200_PMC_UDP; + at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + udpck.pmc_mask = AT91SAM926x_PMC_UDP; + } else if (cpu_is_at91cap9()) { + uhpck.pmc_mask = AT91CAP9_PMC_UHP; + } + at91_sys_write(AT91_CKGR_PLLBR, 0); + + udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); +} + +/* UPLL generated USB full speed clock init */ +static void at91_upll_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 480 MHz from UPLL, + */ + unsigned int usbr = AT91_PMC_USBS_UPLL; + + /* Setup divider by 10 to reach 48 MHz */ + usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV; + + at91_sys_write(AT91_PMC_USB, usbr); + + /* Now set uhpck values */ + uhpck.parent = &utmi_clk; + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); +} + +int at91_clock_init(unsigned long main_clock) +{ + unsigned tmp, freq, mckr; + int i; + + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = at91_sys_read(AT91_CKGR_MCFR); + } while (!(tmp & AT91_PMC_MAINRDY)); + main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16); + } + main_clk.rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); + + if (cpu_has_upll() && !cpu_has_pllb()) { + /* setup UTMI clock as the fourth primary clock + * (instead of pllb) */ + utmi_clk.type |= CLK_TYPE_PRIMARY; + utmi_clk.id = 3; + } + + /* + * USB HS clock init + */ + if (cpu_has_utmi()) + /* + * multiplier is hard-wired to 40 + * (obtain the USB High Speed 480 MHz when input is 12 MHz) + */ + utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + + /* + * USB FS clock init + */ + if (cpu_has_pllb()) + at91_pllb_usbfs_clock_init(main_clock); + if (cpu_has_upll()) + /* assumes that we choose UPLL for USB and not PLLA */ + at91_upll_usbfs_clock_init(main_clock); + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = at91_sys_read(AT91_PMC_MCKR); + mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); + freq = mck.parent->rate_hz; + freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ + if (cpu_is_at91rm9200()) { + mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else if (cpu_is_at91sam9g20()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) ? + freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + if (mckr & AT91_PMC_PDIV) + freq /= 2; /* processor clock division */ + } else { + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } + + /* Register the PMC's standard clocks */ + for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) + list_add_tail(&standard_pmc_clocks[i]->node, &clocks); + + if (cpu_has_pllb()) + list_add_tail(&pllb.node, &clocks); + + if (cpu_has_uhp()) + list_add_tail(&uhpck.node, &clocks); + + if (cpu_has_udpfs()) + list_add_tail(&udpck.node, &clocks); + + if (cpu_has_utmi()) + list_add_tail(&utmi_clk.node, &clocks); + + /* MCK and CPU clock are "always on" */ + clk_enable(&mck); + + return 0; +} + +static int at91_clock_display(void) +{ + if ((!cpu_has_800M_plla() && plla.rate_hz > 209000000) + || (cpu_has_800M_plla() && plla.rate_hz > 800000000)) + pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + + printf("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n", + mck.parent->rate_hz / 1000000, (unsigned) mck.rate_hz / 1000000, + (unsigned) main_clk.rate_hz / 1000000, + ((unsigned) main_clk.rate_hz % 1000000) / 1000); + + return 0; +} +postconsole_initcall(at91_clock_display); + +/* + * Several unused clocks may be active. Turn them off. + */ +static int at91_clock_reset(void) +{ + unsigned long pcdr = 0; + unsigned long scdr = 0; + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (clk->users > 0) + continue; + + if (clk->mode == pmc_periph_mode) + pcdr |= clk->pmc_mask; + + if (clk->mode == pmc_sys_mode) + scdr |= clk->pmc_mask; + + pr_debug("Clocks: disable unused %s\n", clk->name); + } + + at91_sys_write(AT91_PMC_PCDR, pcdr); + at91_sys_write(AT91_PMC_SCDR, scdr); + + return 0; +} +late_initcall(at91_clock_reset); diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h new file mode 100644 index 0000000..6f05732 --- /dev/null +++ b/arch/arm/mach-at91/clock.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-at91/clock.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define CLK_TYPE_PRIMARY 0x1 +#define CLK_TYPE_PLL 0x2 +#define CLK_TYPE_PROGRAMMABLE 0x4 +#define CLK_TYPE_PERIPHERAL 0x8 +#define CLK_TYPE_SYSTEM 0x10 + + +struct clk { + struct list_head node; + const char *name; /* unique clock name */ + const char *function; /* function of the clock */ + struct device_d *dev; /* device associated with function */ + unsigned long rate_hz; + struct clk *parent; + u32 pmc_mask; + void (*mode)(struct clk *, int); + unsigned id:2; /* PCK0..3, or 32k/main/a/b */ + unsigned type; /* clock type */ + u16 users; +}; + + +extern int __init clk_register(struct clk *clk); diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h new file mode 100644 index 0000000..b3a029d --- /dev/null +++ b/arch/arm/mach-at91/generic.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/mach-at91/generic.h + * + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* Clocks */ +extern int __init at91_clock_init(unsigned long main_clock); +struct device_d; +extern void __init at91_clock_associate(const char *id, struct device_d *dev, const char *func); diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 1cafaf7..b257128 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -22,6 +22,7 @@ */ #include <common.h> +#include <linux/clk.h> #include <errno.h> #include <asm/io.h> #include <mach/gpio.h> @@ -245,6 +246,8 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) data->regbase = data->offset + (void __iomem *)AT91_BASE_SYS; + /* enable PIO controller's clock */ + clk_enable(data->clock); /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ if (last && last->id == data->id) diff --git a/arch/arm/mach-at91/include/mach/at91_dbgu.h b/arch/arm/mach-at91/include/mach/at91_dbgu.h new file mode 100644 index 0000000..6dcaa77 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at91_dbgu.h @@ -0,0 +1,66 @@ +/* + * arch/arm/mach-at91/include/mach/at91_dbgu.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Debug Unit (DBGU) - System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91_DBGU_H +#define AT91_DBGU_H + +#ifdef AT91_DBGU +#define AT91_DBGU_CR (AT91_DBGU + 0x00) /* Control Register */ +#define AT91_DBGU_MR (AT91_DBGU + 0x04) /* Mode Register */ +#define AT91_DBGU_IER (AT91_DBGU + 0x08) /* Interrupt Enable Register */ +#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */ +#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */ +#define AT91_DBGU_IDR (AT91_DBGU + 0x0c) /* Interrupt Disable Register */ +#define AT91_DBGU_IMR (AT91_DBGU + 0x10) /* Interrupt Mask Register */ +#define AT91_DBGU_SR (AT91_DBGU + 0x14) /* Status Register */ +#define AT91_DBGU_RHR (AT91_DBGU + 0x18) /* Receiver Holding Register */ +#define AT91_DBGU_THR (AT91_DBGU + 0x1c) /* Transmitter Holding Register */ +#define AT91_DBGU_BRGR (AT91_DBGU + 0x20) /* Baud Rate Generator Register */ + +#define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */ +#define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */ +#define AT91_DBGU_FNR (AT91_DBGU + 0x48) /* Force NTRST Register [SAM9 only] */ +#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */ + +#endif /* AT91_DBGU */ + +/* + * Some AT91 parts that don't have full DEBUG units still support the ID + * and extensions register. + */ +#define AT91_CIDR_VERSION (0x1f << 0) /* Version of the Device */ +#define AT91_CIDR_EPROC (7 << 5) /* Embedded Processor */ +#define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */ +#define AT91_CIDR_NVPSIZ2 (0xf << 12) /* Second Nonvolatile Program Memory Size */ +#define AT91_CIDR_SRAMSIZ (0xf << 16) /* Internal SRAM Size */ +#define AT91_CIDR_SRAMSIZ_1K (1 << 16) +#define AT91_CIDR_SRAMSIZ_2K (2 << 16) +#define AT91_CIDR_SRAMSIZ_112K (4 << 16) +#define AT91_CIDR_SRAMSIZ_4K (5 << 16) +#define AT91_CIDR_SRAMSIZ_80K (6 << 16) +#define AT91_CIDR_SRAMSIZ_160K (7 << 16) +#define AT91_CIDR_SRAMSIZ_8K (8 << 16) +#define AT91_CIDR_SRAMSIZ_16K (9 << 16) +#define AT91_CIDR_SRAMSIZ_32K (10 << 16) +#define AT91_CIDR_SRAMSIZ_64K (11 << 16) +#define AT91_CIDR_SRAMSIZ_128K (12 << 16) +#define AT91_CIDR_SRAMSIZ_256K (13 << 16) +#define AT91_CIDR_SRAMSIZ_96K (14 << 16) +#define AT91_CIDR_SRAMSIZ_512K (15 << 16) +#define AT91_CIDR_ARCH (0xff << 20) /* Architecture Identifier */ +#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */ +#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */ + +#endif diff --git a/arch/arm/mach-at91/include/mach/clk.h b/arch/arm/mach-at91/include/mach/clk.h deleted file mode 100644 index a9c0683..0000000 --- a/arch/arm/mach-at91/include/mach/clk.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * (C) Copyright 2007 - * Stelian Pop <stelian.pop@leadtechdesign.com> - * Lead Tech Design <www.leadtechdesign.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_CLK_H__ -#define __ASM_ARM_ARCH_CLK_H__ - -#include <mach/hardware.h> - -static inline unsigned long get_macb_pclk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -static inline unsigned long get_usart_clk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -#endif /* __ASM_ARM_ARCH_CLK_H__ */ diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h new file mode 100644 index 0000000..c554c3e --- /dev/null +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -0,0 +1,118 @@ +/* + * arch/arm/mach-at91/include/mach/cpu.h + * + * Copyright (C) 2006 SAN People + * + * 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. + * + */ + +#ifndef __ASM_ARCH_CPU_H +#define __ASM_ARCH_CPU_H + +#include <mach/hardware.h> +#include <mach/at91_dbgu.h> + + +#define ARCH_ID_AT91RM9200 0x09290780 +#define ARCH_ID_AT91SAM9260 0x019803a0 +#define ARCH_ID_AT91SAM9261 0x019703a0 +#define ARCH_ID_AT91SAM9263 0x019607a0 +#define ARCH_ID_AT91SAM9G20 0x019905a0 +#define ARCH_ID_AT91SAM9RL64 0x019b03a0 +#define ARCH_ID_AT91CAP9 0x039A03A0 + +#define ARCH_ID_AT91SAM9XE128 0x329973a0 +#define ARCH_ID_AT91SAM9XE256 0x329a93a0 +#define ARCH_ID_AT91SAM9XE512 0x329aa3a0 + +#define ARCH_ID_AT91M40800 0x14080044 +#define ARCH_ID_AT91R40807 0x44080746 +#define ARCH_ID_AT91M40807 0x14080745 +#define ARCH_ID_AT91R40008 0x44000840 + +static inline unsigned long at91_cpu_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION); +} + + +#define ARCH_FAMILY_AT91X92 0x09200000 +#define ARCH_FAMILY_AT91SAM9 0x01900000 +#define ARCH_FAMILY_AT91SAM9XE 0x02900000 + +static inline unsigned long at91_arch_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH); +} + +#ifdef CONFIG_ARCH_AT91CAP9 +#include <mach/at91_pmc.h> + +#define ARCH_REVISION_CAP9_B 0x399 +#define ARCH_REVISION_CAP9_C 0x601 + +static inline unsigned long at91cap9_rev_identify(void) +{ + return (at91_sys_read(AT91_PMC_VER)); +} +#endif + +#ifdef CONFIG_ARCH_AT91RM9200 +#define cpu_is_at91rm9200() (at91_cpu_identify() == ARCH_ID_AT91RM9200) +#else +#define cpu_is_at91rm9200() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9260 +#define cpu_is_at91sam9xe() (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE) +#define cpu_is_at91sam9260() ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe()) +#else +#define cpu_is_at91sam9xe() (0) +#define cpu_is_at91sam9260() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G20 +#define cpu_is_at91sam9g20() (at91_cpu_identify() == ARCH_ID_AT91SAM9G20) +#else +#define cpu_is_at91sam9g20() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9261 +#define cpu_is_at91sam9261() (at91_cpu_identify() == ARCH_ID_AT91SAM9261) +#else +#define cpu_is_at91sam9261() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9263 +#define cpu_is_at91sam9263() (at91_cpu_identify() == ARCH_ID_AT91SAM9263) +#else +#define cpu_is_at91sam9263() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9RL +#define cpu_is_at91sam9rl() (at91_cpu_identify() == ARCH_ID_AT91SAM9RL64) +#else +#define cpu_is_at91sam9rl() (0) +#endif + +#ifdef CONFIG_ARCH_AT91CAP9 +#define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) +#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) +#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C) +#else +#define cpu_is_at91cap9() (0) +#define cpu_is_at91cap9_revB() (0) +#define cpu_is_at91cap9_revC() (0) +#endif + +/* + * Since this is ARM, we will never run on any AVR32 CPU. But these + * definitions may reduce clutter in common drivers. + */ +#define cpu_is_at32ap7000() (0) + +#endif diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h index 76d53ba..7e1a9a8 100644 --- a/arch/arm/mach-at91/include/mach/gpio.h +++ b/arch/arm/mach-at91/include/mach/gpio.h @@ -241,6 +241,7 @@ struct at91_gpio_bank { struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */ unsigned short id; /* peripheral ID */ unsigned long offset; /* offset from system peripheral base */ + struct clk *clock; }; extern int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 4feeed0..6864119 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -48,7 +48,7 @@ #include <errno.h> #include <asm/io.h> #include <mach/board.h> -#include <mach/clk.h> +#include <linux/clk.h> #include "macb.h" @@ -412,6 +412,9 @@ static int macb_probe(struct device_d *dev) unsigned long macb_hz; u32 ncfgr; struct at91_ether_platform_data *pdata; +#if defined(CONFIG_ARCH_AT91) + struct clk *pclk; +#endif if (!dev->platform_data) { printf("macb: no platform_data\n"); @@ -450,7 +453,13 @@ static int macb_probe(struct device_d *dev) * Do some basic initialization so that we at least can talk * to the PHY */ +#if defined(CONFIG_ARCH_AT91) + pclk = clk_get(dev, "macb_clk"); + clk_enable(pclk); + macb_hz = clk_get_rate(pclk); +#else macb_hz = get_macb_pclk_rate(0); +#endif if (macb_hz < 20000000) ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); else if (macb_hz < 40000000) diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c index e9e8116..b99ec4d 100644 --- a/drivers/serial/atmel.c +++ b/drivers/serial/atmel.c @@ -22,7 +22,7 @@ #include <init.h> #include <malloc.h> #include <asm/io.h> -#include <mach/clk.h> +#include <linux/clk.h> /* USART3 register offsets */ #define USART3_CR 0x0000 @@ -309,6 +309,21 @@ << USART3_##name##_OFFSET)) \ | USART3_BF(name,value)) +/* + * We wrap our port structure around the generic console_device. + */ +struct atmel_uart_port { + struct console_device uart; /* uart */ + struct clk *clk; /* uart clock */ + u32 uartclk; +}; + +static inline struct atmel_uart_port * +to_atmel_uart_port(struct console_device *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + static void atmel_serial_putc(struct console_device *cdev, char c) { struct device_d *dev = cdev->dev; @@ -336,16 +351,15 @@ static int atmel_serial_getc(struct console_device *cdev) static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); unsigned long divisor; - unsigned long usart_hz; /* * Master Clock * Baud Rate = -------------- * 16 * CD */ - usart_hz = get_usart_clk_rate(0); - divisor = (usart_hz / 16 + baudrate / 2) / baudrate; + divisor = (uart->uartclk / 16 + baudrate / 2) / baudrate; writel(USART3_BF(CD, divisor), dev->map_base + USART3_BRGR); return 0; @@ -359,6 +373,11 @@ static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) static int atmel_serial_init_port(struct console_device *cdev) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); + + uart->clk = clk_get(dev, "usart"); + clk_enable(uart->clk); + uart->uartclk = clk_get_rate(uart->clk); writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), dev->map_base + USART3_CR); @@ -376,9 +395,12 @@ static int atmel_serial_init_port(struct console_device *cdev) static int atmel_serial_probe(struct device_d *dev) { + struct atmel_uart_port *uart; struct console_device *cdev; - cdev = malloc(sizeof(struct console_device)); + uart = malloc(sizeof(struct atmel_uart_port)); + + cdev = &uart->uart; dev->type_data = cdev; cdev->dev = dev; cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/3] at91: implement clock framework 2010-08-03 12:53 ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 20:23 ` Sascha Hauer 2010-08-04 1:33 ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 0 replies; 11+ messages in thread From: Sascha Hauer @ 2010-08-03 20:23 UTC (permalink / raw) To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox Hi Jean-Christophe, That was fast ;) On Tue, Aug 03, 2010 at 02:53:39PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote: > this implementation is based on linux one > it will calculate all the clock dynamically instead of statictly > this will use also the new clock framework I think it's a good idea to leave a pointer to the Linux version this code is from. This will help us find relevant changes for barebox in the Linux history. > > + > +static struct clk *periph_clocks[] = { > + &pioA_clk, > + &pioB_clk, > + &pioC_clk, > + &adc_clk, > + &usart0_clk, > + &usart1_clk, > + &usart2_clk, > + &mmc_clk, > + &udc_clk, > + &twi_clk, > + &spi0_clk, > + &spi1_clk, > + &ssc_clk, > + &tc0_clk, > + &tc1_clk, > + &tc2_clk, > + &ohci_clk, > + &macb_clk, > + &isi_clk, > + &usart3_clk, > + &usart4_clk, > + &usart5_clk, > + &tc3_clk, > + &tc4_clk, > + &tc5_clk, > + // irq0 .. irq2 > +}; > + > +/* > + * The two programmable clocks. > + * You must configure pin multiplexing to bring these signals out. > + */ > +static struct clk pck0 = { > + .name = "pck0", > + .pmc_mask = AT91_PMC_PCK0, > + .type = CLK_TYPE_PROGRAMMABLE, > + .id = 0, > +}; > +static struct clk pck1 = { > + .name = "pck1", > + .pmc_mask = AT91_PMC_PCK1, > + .type = CLK_TYPE_PROGRAMMABLE, > + .id = 1, > +}; > + > +static void __init at91sam9260_register_clocks(void) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) > + clk_register(periph_clocks[i]); > + > + clk_register(&pck0); > + clk_register(&pck1); Any special reason these are not registered in the array above other that they are not peripheral clocks? I just saw that it's the same in Linux, so probably this is the reason. -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/3 v2] at91: implement clock framework 2010-08-03 12:53 ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 20:23 ` Sascha Hauer @ 2010-08-04 1:33 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-04 5:20 ` Baruch Siach 2010-08-04 6:12 ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 2 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04 1:33 UTC (permalink / raw) To: barebox this implementation is based on linux one (v2.6.35-rc5-76-gd0c6f62) it will calculate all the clock dynamically instead of statictly this will use also the new clock framework it will also print the clock status after the console init Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- v2: upadate against mainline kernel and add ref on which revision it's based on Best Regards, J. arch/arm/boards/at91sam9260ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/init.c | 3 - arch/arm/boards/mmccpu/config.h | 2 +- arch/arm/boards/mmccpu/init.c | 3 - arch/arm/boards/pm9263/config.h | 2 +- arch/arm/boards/pm9263/init.c | 3 - arch/arm/mach-at91/Makefile | 2 +- arch/arm/mach-at91/at91sam9260.c | 207 ++++++++ arch/arm/mach-at91/at91sam9260_devices.c | 18 +- arch/arm/mach-at91/at91sam9263.c | 217 ++++++++ arch/arm/mach-at91/at91sam9263_devices.c | 13 +- arch/arm/mach-at91/clock.c | 718 +++++++++++++++++++++++++++ arch/arm/mach-at91/clock.h | 31 ++ arch/arm/mach-at91/generic.h | 14 + arch/arm/mach-at91/gpio.c | 3 + arch/arm/mach-at91/include/mach/at91_dbgu.h | 66 +++ arch/arm/mach-at91/include/mach/clk.h | 39 -- arch/arm/mach-at91/include/mach/cpu.h | 158 ++++++ arch/arm/mach-at91/include/mach/gpio.h | 1 + drivers/net/macb.c | 11 +- drivers/serial/atmel.c | 32 +- 22 files changed, 1472 insertions(+), 75 deletions(-) create mode 100644 arch/arm/mach-at91/clock.c create mode 100644 arch/arm/mach-at91/clock.h create mode 100644 arch/arm/mach-at91/generic.h create mode 100644 arch/arm/mach-at91/include/mach/at91_dbgu.h delete mode 100644 arch/arm/mach-at91/include/mach/clk.h create mode 100644 arch/arm/mach-at91/include/mach/cpu.h diff --git a/arch/arm/boards/at91sam9260ek/config.h b/arch/arm/boards/at91sam9260ek/config.h index afd8563..006820c 100644 --- a/arch/arm/boards/at91sam9260ek/config.h +++ b/arch/arm/boards/at91sam9260ek/config.h @@ -1,6 +1,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 /* 18.432 MHz crystal */ #endif /* __CONFIG_H */ diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h index 9cc8af2..bc33227 100644 --- a/arch/arm/boards/at91sam9263ek/config.h +++ b/arch/arm/boards/at91sam9263ek/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 100000000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 16367660 /* 16.367 MHz crystal */ #define MASTER_PLL_MUL 171 #define MASTER_PLL_DIV 14 diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c index 21803ca..61cd295 100644 --- a/arch/arm/boards/at91sam9263ek/init.c +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -108,9 +108,6 @@ static int at91sam9263ek_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); ek_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h index 1133b8f..422ac09 100644 --- a/arch/arm/boards/mmccpu/config.h +++ b/arch/arm/boards/mmccpu/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ +#define AT91_M1IN_CLOCK 18432000 /* values */ #define MASTER_PLL_MUL 54 diff --git a/arch/arm/boards/mmccpu/init.c b/arch/arm/boards/mmccpu/init.c index e010a83..9a7d930 100644 --- a/arch/arm/boards/mmccpu/init.c +++ b/arch/arm/boards/mmccpu/init.c @@ -58,9 +58,6 @@ static int mmccpu_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(128 * 1024 * 1024); at91_add_device_eth(&macb_pdata); register_device(&cfi_dev); diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h index 9a9c5cd..5252df2 100644 --- a/arch/arm/boards/pm9263/config.h +++ b/arch/arm/boards/pm9263/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 #define MASTER_PLL_DIV 6 #define MASTER_PLL_MUL 65 diff --git a/arch/arm/boards/pm9263/init.c b/arch/arm/boards/pm9263/init.c index 88b91ea..d5ed921 100644 --- a/arch/arm/boards/pm9263/init.c +++ b/arch/arm/boards/pm9263/init.c @@ -107,9 +107,6 @@ static int pm9263_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); pm_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index c848919..0f55883 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -1,4 +1,4 @@ -obj-y += clocksource.o gpio.o +obj-y += clock.o clocksource.o gpio.o obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 1a6e356..30d1a6a 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -2,22 +2,229 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "generic.h" +#include "clock.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioC_clk = { + .name = "pioC_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk adc_clk = { + .name = "adc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ADC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc_clk = { + .name = "mci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_MCI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc_clk = { + .name = "ssc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SSC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9260_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart3_clk = { + .name = "usart3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart4_clk = { + .name = "usart4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart5_clk = { + .name = "usart5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US5, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc3_clk = { + .name = "tc3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc4_clk = { + .name = "tc4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc5_clk = { + .name = "tc5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC5, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioC_clk, + &adc_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc_clk, + &udc_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc_clk, + &tc0_clk, + &tc1_clk, + &tc2_clk, + &ohci_clk, + &macb_clk, + &isi_clk, + &usart3_clk, + &usart4_clk, + &usart5_clk, + &tc3_clk, + &tc4_clk, + &tc5_clk, + // irq0 .. irq2 +}; + +/* + * The two programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; + +static void __init at91sam9260_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9260_gpio[] = { { .id = AT91SAM9260_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9260_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9260_ID_PIOC, .offset = AT91_PIOC, + .clock = &pioC_clk, } }; static int at91sam9260_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9260_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9260_gpio, 3); return 0; diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 0cfe913..398a721 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data sram_pdata = { .name = "sram0", .flags = DEVFS_RDWR, @@ -107,8 +109,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -233,37 +233,37 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9260_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9260_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9260_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; case AT91SAM9260_ID_US3: configure_usart3_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US3); + at91_clock_associate("usart3_clk", &uart3_serial_device, "usart"); register_device(&uart3_serial_device); break; case AT91SAM9260_ID_US4: configure_usart4_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US4); + at91_clock_associate("usart4_clk", &uart4_serial_device, "usart"); register_device(&uart4_serial_device); break; case AT91SAM9260_ID_US5: configure_usart5_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US5); + at91_clock_associate("usart5_clk", &uart5_serial_device, "usart"); register_device(&uart5_serial_device); break; default: diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 472b619..b0e3193 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -2,28 +2,245 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "clock.h" +#include "generic.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioCDE_clk = { + .name = "pioCDE_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOCDE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc0_clk = { + .name = "mci0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc1_clk = { + .name = "mci1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk can_clk = { + .name = "can_clk", + .pmc_mask = 1 << AT91SAM9263_ID_CAN, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ac97_clk = { + .name = "ac97_clk", + .pmc_mask = 1 << AT91SAM9263_ID_AC97C, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tcb_clk = { + .name = "tcb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TCB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pwm_clk = { + .name = "pwm_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PWMC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk dma_clk = { + .name = "dma_clk", + .pmc_mask = 1 << AT91SAM9263_ID_DMA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twodge_clk = { + .name = "2dge_clk", + .pmc_mask = 1 << AT91SAM9263_ID_2DGE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk lcdc_clk = { + .name = "lcdc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_LCDC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioCDE_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc0_clk, + &mmc1_clk, + &can_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc0_clk, + &ssc1_clk, + &ac97_clk, + &tcb_clk, + &pwm_clk, + &macb_clk, + &twodge_clk, + &udc_clk, + &isi_clk, + &lcdc_clk, + &dma_clk, + &ohci_clk, + // irq0 .. irq1 +}; + +/* + * The four programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 3, +}; + +static void __init at91sam9263_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); + clk_register(&pck2); + clk_register(&pck3); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9263_gpio[] = { { .id = AT91SAM9263_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9263_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOC, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOD, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOE, + .clock = &pioCDE_clk, } }; static int at91sam9263_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9263_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9263_gpio, 5); return 0; diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 50a6348..7ebc32c 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data ram_pdata = { .name = "ram0", .flags = DEVFS_RDWR, @@ -106,9 +108,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_PIOA | - 1 << AT91SAM9263_ID_PIOCDE); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -184,22 +183,22 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9263_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9263_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9263_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; default: diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c new file mode 100644 index 0000000..6fd09d5 --- /dev/null +++ b/arch/arm/mach-at91/clock.c @@ -0,0 +1,718 @@ +/* + * linux/arch/arm/mach-at91/clock.c + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * + * 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. + */ + +#include <common.h> +#include <linux/list.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <init.h> + +#include <mach/hardware.h> +#include <mach/io.h> +#include <mach/at91_pmc.h> +#include <mach/cpu.h> + +#include "clock.h" +#include "generic.h" + +/* + * There's a lot more which can be done with clocks, including cpufreq + * integration, slow clock mode support (for system suspend), letting + * PLLB be used at other rates (on boards that don't need USB), etc. + */ + +#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY) +#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE) +#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL) +#define clk_is_sys(x) ((x)->type & CLK_TYPE_SYSTEM) + + +/* + * Chips have some kind of clocks : group them by functionality + */ +#define cpu_has_utmi() ( cpu_is_at91cap9() \ + || cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45()) + +#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ + || cpu_is_at91sam9g45()) + +#define cpu_has_300M_plla() (cpu_is_at91sam9g10()) + +#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) + +#define cpu_has_upll() (cpu_is_at91sam9g45()) + +/* USB host HS & FS */ +#define cpu_has_uhp() (!cpu_is_at91sam9rl()) + +/* USB device FS only */ +#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) + +static LIST_HEAD(clocks); + +static u32 at91_pllb_usb_init; + +/* + * Four primary clock sources: two crystal oscillators (32K, main), and + * two PLLs. PLLA usually runs the master clock; and PLLB must run at + * 48 MHz (unless no USB function clocks are needed). The main clock and + * both PLLs are turned off to run in "slow clock mode" (system suspend). + */ +static struct clk clk32k = { + .name = "clk32k", + .rate_hz = AT91_SLOW_CLOCK, + .users = 1, /* always on */ + .id = 0, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk main_clk = { + .name = "main", + .pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */ + .id = 1, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk plla = { + .name = "plla", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */ + .id = 2, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pllb_mode(struct clk *clk, int is_on) +{ + u32 value; + + if (is_on) { + is_on = AT91_PMC_LOCKB; + value = at91_pllb_usb_init; + } else + value = 0; + + // REVISIT: Add work-around for AT91RM9200 Errata #26 ? + at91_sys_write(AT91_CKGR_PLLBR, value); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on); +} + +static struct clk pllb = { + .name = "pllb", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */ + .mode = pllb_mode, + .id = 3, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pmc_sys_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_SCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); +} + +static void pmc_uckr_mode(struct clk *clk, int is_on) +{ + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (cpu_is_at91sam9g45()) { + if (is_on) + uckr |= AT91_PMC_BIASEN; + else + uckr &= ~AT91_PMC_BIASEN; + } + + if (is_on) { + is_on = AT91_PMC_LOCKU; + at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); + } else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask)); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on); +} + +/* USB function clocks (PLLB must be 48 MHz) */ +static struct clk udpck = { + .name = "udpck", + .parent = &pllb, + .mode = pmc_sys_mode, +}; +static struct clk utmi_clk = { + .name = "utmi_clk", + .parent = &main_clk, + .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */ + .mode = pmc_uckr_mode, + .type = CLK_TYPE_PLL, +}; +static struct clk uhpck = { + .name = "uhpck", + /*.parent = ... we choose parent at runtime */ + .mode = pmc_sys_mode, +}; + + +/* + * The master clock is divided from the CPU clock (by 1-4). It's used for + * memory, interfaces to on-chip peripherals, the AIC, and sometimes more + * (e.g baud rate generation). It's sourced from one of the primary clocks. + */ +static struct clk mck = { + .name = "mck", + .pmc_mask = AT91_PMC_MCKRDY, /* in PMC_SR */ +}; + +static void pmc_periph_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_PCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask); +} + +static struct clk *at91_css_to_clk(unsigned long css) +{ + switch (css) { + case AT91_PMC_CSS_SLOW: + return &clk32k; + case AT91_PMC_CSS_MAIN: + return &main_clk; + case AT91_PMC_CSS_PLLA: + return &plla; + case AT91_PMC_CSS_PLLB: + if (cpu_has_upll()) + /* CSS_PLLB == CSS_UPLL */ + return &utmi_clk; + else if (cpu_has_pllb()) + return &pllb; + } + + return NULL; +} + +/* + * Associate a particular clock with a function (eg, "uart") and device. + * The drivers can then request the same 'function' with several different + * devices and not care about which clock name to use. + */ +void at91_clock_associate(const char *id, struct device_d *dev, const char *func) +{ + struct clk *clk = clk_get(NULL, id); + + if (!dev || !clk || !IS_ERR(clk_get(dev, func))) + return; + + clk->function = func; + clk->dev = dev; +} + +/* clocks cannot be de-registered no refcounting necessary */ +struct clk *clk_get(struct device_d *dev, const char *id) +{ + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (strcmp(id, clk->name) == 0) + return clk; + if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0) + return clk; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + if (clk->users++ == 0 && clk->mode) + clk->mode(clk, 1); +} + +int clk_enable(struct clk *clk) +{ + __clk_enable(clk); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +static void __clk_disable(struct clk *clk) +{ + BUG_ON(clk->users == 0); + if (--clk->users == 0 && clk->mode) + clk->mode(clk, 0); + if (clk->parent) + __clk_disable(clk->parent); +} + +void clk_disable(struct clk *clk) +{ + __clk_disable(clk); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + for (;;) { + rate = clk->rate_hz; + if (rate || !clk->parent) + break; + clk = clk->parent; + } + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +/*------------------------------------------------------------------------*/ + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + +/* + * For now, only the programmable clocks support reparenting (MCK could + * do this too, with care) or rate changing (the PLLs could do this too, + * ditto MCK but that's more for cpufreq). Drivers may reparent to get + * a better rate match; we don't. + */ + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + unsigned long prev = ULONG_MAX; + + if (!clk_is_programmable(clk)) + return -EINVAL; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual > rate) + prev = actual; + + if (actual && actual <= rate) { + if ((prev - rate) < (rate - actual)) { + actual = prev; + prescale--; + } + break; + } + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk_is_programmable(clk)) + return -EINVAL; + if (clk->users) + return -EBUSY; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) { + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + pckr &= AT91_PMC_CSS; /* clock selection */ + pckr |= prescale << 2; + at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); + clk->rate_hz = actual; + break; + } + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + + if (clk->users) + return -EBUSY; + if (!clk_is_primary(parent) || !clk_is_programmable(clk)) + return -EINVAL; + + if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB) + return -EINVAL; + + clk->rate_hz = parent->rate_hz; + clk->parent = parent; + at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id); + + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +/* establish PCK0..PCKN parentage and rate */ +static void init_programmable_clock(struct clk *clk) +{ + struct clk *parent; + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + parent = at91_css_to_clk(pckr & AT91_PMC_CSS); + clk->parent = parent; + clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2)); +} + +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + +/*------------------------------------------------------------------------*/ + +/* Register a new clock */ +int clk_register(struct clk *clk) +{ + if (clk_is_peripheral(clk)) { + clk->parent = &mck; + clk->mode = pmc_periph_mode; + list_add_tail(&clk->node, &clocks); + } + else if (clk_is_sys(clk)) { + clk->parent = &mck; + clk->mode = pmc_sys_mode; + + list_add_tail(&clk->node, &clocks); + } +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + else if (clk_is_programmable(clk)) { + clk->mode = pmc_sys_mode; + init_programmable_clock(clk); + list_add_tail(&clk->node, &clocks); + } +#endif + + return 0; +} + + +/*------------------------------------------------------------------------*/ + +static u32 at91_pll_rate(struct clk *pll, u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + + return freq; +} + +static u32 at91_usb_rate(struct clk *pll, u32 freq, u32 reg) +{ + if (pll == &pllb && (reg & AT91_PMC_USB96M)) + return freq / 2; + else + return freq; +} + +static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + * Warning: some newer products need 2MHz min. + */ + input = main_freq / i; + if (cpu_is_at91sam9g20() && input < 2000000) + continue; + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; + if (cpu_is_at91sam9g20() && mul > 63) + continue; + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} + +static struct clk *const standard_pmc_clocks[] = { + /* four primary clocks */ + &clk32k, + &main_clk, + &plla, + + /* MCK */ + &mck +}; + +/* PLLB generated USB full speed clock init */ +static void at91_pllb_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + uhpck.parent = &pllb; + + at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M; + pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); + if (cpu_is_at91rm9200()) { + uhpck.pmc_mask = AT91RM9200_PMC_UHP; + udpck.pmc_mask = AT91RM9200_PMC_UDP; + at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || + cpu_is_at91sam9263() || cpu_is_at91sam9g20() || + cpu_is_at91sam9g10() || cpu_is_at572d940hf()) { + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + udpck.pmc_mask = AT91SAM926x_PMC_UDP; + } else if (cpu_is_at91cap9()) { + uhpck.pmc_mask = AT91CAP9_PMC_UHP; + } + at91_sys_write(AT91_CKGR_PLLBR, 0); + + udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); +} + +/* UPLL generated USB full speed clock init */ +static void at91_upll_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 480 MHz from UPLL, + */ + unsigned int usbr = AT91_PMC_USBS_UPLL; + + /* Setup divider by 10 to reach 48 MHz */ + usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV; + + at91_sys_write(AT91_PMC_USB, usbr); + + /* Now set uhpck values */ + uhpck.parent = &utmi_clk; + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); +} + +static int pll_overclock = 0; + +int at91_clock_init(unsigned long main_clock) +{ + unsigned tmp, freq, mckr; + int i; + + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = at91_sys_read(AT91_CKGR_MCFR); + } while (!(tmp & AT91_PMC_MAINRDY)); + main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16); + } + main_clk.rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); + if (cpu_has_300M_plla()) { + if (plla.rate_hz > 300000000) + pll_overclock = 1; + } else if (cpu_has_800M_plla()) { + if (plla.rate_hz > 800000000) + pll_overclock = 1; + } else { + if (plla.rate_hz > 209000000) + pll_overclock = 1; + } + + if (cpu_is_at91sam9g45()) { + mckr = at91_sys_read(AT91_PMC_MCKR); + plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ + } + + if (!cpu_has_pllb() && cpu_has_upll()) { + /* setup UTMI clock as the fourth primary clock + * (instead of pllb) */ + utmi_clk.type |= CLK_TYPE_PRIMARY; + utmi_clk.id = 3; + } + + /* + * USB HS clock init + */ + if (cpu_has_utmi()) { + /* + * multiplier is hard-wired to 40 + * (obtain the USB High Speed 480 MHz when input is 12 MHz) + */ + utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + } + + /* + * USB FS clock init + */ + if (cpu_has_pllb()) + at91_pllb_usbfs_clock_init(main_clock); + if (cpu_has_upll()) + /* assumes that we choose UPLL for USB and not PLLA */ + at91_upll_usbfs_clock_init(main_clock); + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = at91_sys_read(AT91_PMC_MCKR); + mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); + freq = mck.parent->rate_hz; + freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ + if (cpu_is_at91rm9200()) { + mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else if (cpu_is_at91sam9g20()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) ? + freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + if (mckr & AT91_PMC_PDIV) + freq /= 2; /* processor clock division */ + } else if (cpu_is_at91sam9g45()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? + freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else { + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } + + /* Register the PMC's standard clocks */ + for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) + list_add_tail(&standard_pmc_clocks[i]->node, &clocks); + + if (cpu_has_pllb()) + list_add_tail(&pllb.node, &clocks); + + if (cpu_has_uhp()) + list_add_tail(&uhpck.node, &clocks); + + if (cpu_has_udpfs()) + list_add_tail(&udpck.node, &clocks); + + if (cpu_has_utmi()) + list_add_tail(&utmi_clk.node, &clocks); + + /* MCK and CPU clock are "always on" */ + clk_enable(&mck); + + return 0; +} + +static int at91_clock_display(void) +{ + if (pll_overclock) + pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + + printf("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n", + mck.parent->rate_hz / 1000000, (unsigned) mck.rate_hz / 1000000, + (unsigned) main_clk.rate_hz / 1000000, + ((unsigned) main_clk.rate_hz % 1000000) / 1000); + + return 0; +} +postconsole_initcall(at91_clock_display); + +/* + * Several unused clocks may be active. Turn them off. + */ +static int at91_clock_reset(void) +{ + unsigned long pcdr = 0; + unsigned long scdr = 0; + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (clk->users > 0) + continue; + + if (clk->mode == pmc_periph_mode) + pcdr |= clk->pmc_mask; + + if (clk->mode == pmc_sys_mode) + scdr |= clk->pmc_mask; + + pr_debug("Clocks: disable unused %s\n", clk->name); + } + + at91_sys_write(AT91_PMC_PCDR, pcdr); + at91_sys_write(AT91_PMC_SCDR, scdr); + + return 0; +} +late_initcall(at91_clock_reset); diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h new file mode 100644 index 0000000..c8ecd0c --- /dev/null +++ b/arch/arm/mach-at91/clock.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-at91/clock.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define CLK_TYPE_PRIMARY 0x1 +#define CLK_TYPE_PLL 0x2 +#define CLK_TYPE_PROGRAMMABLE 0x4 +#define CLK_TYPE_PERIPHERAL 0x8 +#define CLK_TYPE_SYSTEM 0x10 + + +struct clk { + struct list_head node; + const char *name; /* unique clock name */ + const char *function; /* function of the clock */ + struct device_d *dev; /* device associated with function */ + unsigned long rate_hz; + struct clk *parent; + u32 pmc_mask; + void (*mode)(struct clk *, int); + unsigned id:3; /* PCK0..4, or 32k/main/a/b */ + unsigned type; /* clock type */ + u16 users; +}; + + +extern int __init clk_register(struct clk *clk); diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h new file mode 100644 index 0000000..b3a029d --- /dev/null +++ b/arch/arm/mach-at91/generic.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/mach-at91/generic.h + * + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* Clocks */ +extern int __init at91_clock_init(unsigned long main_clock); +struct device_d; +extern void __init at91_clock_associate(const char *id, struct device_d *dev, const char *func); diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 1cafaf7..b257128 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -22,6 +22,7 @@ */ #include <common.h> +#include <linux/clk.h> #include <errno.h> #include <asm/io.h> #include <mach/gpio.h> @@ -245,6 +246,8 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) data->regbase = data->offset + (void __iomem *)AT91_BASE_SYS; + /* enable PIO controller's clock */ + clk_enable(data->clock); /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ if (last && last->id == data->id) diff --git a/arch/arm/mach-at91/include/mach/at91_dbgu.h b/arch/arm/mach-at91/include/mach/at91_dbgu.h new file mode 100644 index 0000000..6dcaa77 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at91_dbgu.h @@ -0,0 +1,66 @@ +/* + * arch/arm/mach-at91/include/mach/at91_dbgu.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Debug Unit (DBGU) - System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91_DBGU_H +#define AT91_DBGU_H + +#ifdef AT91_DBGU +#define AT91_DBGU_CR (AT91_DBGU + 0x00) /* Control Register */ +#define AT91_DBGU_MR (AT91_DBGU + 0x04) /* Mode Register */ +#define AT91_DBGU_IER (AT91_DBGU + 0x08) /* Interrupt Enable Register */ +#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */ +#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */ +#define AT91_DBGU_IDR (AT91_DBGU + 0x0c) /* Interrupt Disable Register */ +#define AT91_DBGU_IMR (AT91_DBGU + 0x10) /* Interrupt Mask Register */ +#define AT91_DBGU_SR (AT91_DBGU + 0x14) /* Status Register */ +#define AT91_DBGU_RHR (AT91_DBGU + 0x18) /* Receiver Holding Register */ +#define AT91_DBGU_THR (AT91_DBGU + 0x1c) /* Transmitter Holding Register */ +#define AT91_DBGU_BRGR (AT91_DBGU + 0x20) /* Baud Rate Generator Register */ + +#define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */ +#define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */ +#define AT91_DBGU_FNR (AT91_DBGU + 0x48) /* Force NTRST Register [SAM9 only] */ +#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */ + +#endif /* AT91_DBGU */ + +/* + * Some AT91 parts that don't have full DEBUG units still support the ID + * and extensions register. + */ +#define AT91_CIDR_VERSION (0x1f << 0) /* Version of the Device */ +#define AT91_CIDR_EPROC (7 << 5) /* Embedded Processor */ +#define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */ +#define AT91_CIDR_NVPSIZ2 (0xf << 12) /* Second Nonvolatile Program Memory Size */ +#define AT91_CIDR_SRAMSIZ (0xf << 16) /* Internal SRAM Size */ +#define AT91_CIDR_SRAMSIZ_1K (1 << 16) +#define AT91_CIDR_SRAMSIZ_2K (2 << 16) +#define AT91_CIDR_SRAMSIZ_112K (4 << 16) +#define AT91_CIDR_SRAMSIZ_4K (5 << 16) +#define AT91_CIDR_SRAMSIZ_80K (6 << 16) +#define AT91_CIDR_SRAMSIZ_160K (7 << 16) +#define AT91_CIDR_SRAMSIZ_8K (8 << 16) +#define AT91_CIDR_SRAMSIZ_16K (9 << 16) +#define AT91_CIDR_SRAMSIZ_32K (10 << 16) +#define AT91_CIDR_SRAMSIZ_64K (11 << 16) +#define AT91_CIDR_SRAMSIZ_128K (12 << 16) +#define AT91_CIDR_SRAMSIZ_256K (13 << 16) +#define AT91_CIDR_SRAMSIZ_96K (14 << 16) +#define AT91_CIDR_SRAMSIZ_512K (15 << 16) +#define AT91_CIDR_ARCH (0xff << 20) /* Architecture Identifier */ +#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */ +#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */ + +#endif diff --git a/arch/arm/mach-at91/include/mach/clk.h b/arch/arm/mach-at91/include/mach/clk.h deleted file mode 100644 index a9c0683..0000000 --- a/arch/arm/mach-at91/include/mach/clk.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * (C) Copyright 2007 - * Stelian Pop <stelian.pop@leadtechdesign.com> - * Lead Tech Design <www.leadtechdesign.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_CLK_H__ -#define __ASM_ARM_ARCH_CLK_H__ - -#include <mach/hardware.h> - -static inline unsigned long get_macb_pclk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -static inline unsigned long get_usart_clk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -#endif /* __ASM_ARM_ARCH_CLK_H__ */ diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h new file mode 100644 index 0000000..833659d --- /dev/null +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -0,0 +1,158 @@ +/* + * arch/arm/mach-at91/include/mach/cpu.h + * + * Copyright (C) 2006 SAN People + * + * 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. + * + */ + +#ifndef __ASM_ARCH_CPU_H +#define __ASM_ARCH_CPU_H + +#include <mach/hardware.h> +#include <mach/at91_dbgu.h> + + +#define ARCH_ID_AT91RM9200 0x09290780 +#define ARCH_ID_AT91SAM9260 0x019803a0 +#define ARCH_ID_AT91SAM9261 0x019703a0 +#define ARCH_ID_AT91SAM9263 0x019607a0 +#define ARCH_ID_AT91SAM9G10 0x019903a0 +#define ARCH_ID_AT91SAM9G20 0x019905a0 +#define ARCH_ID_AT91SAM9RL64 0x019b03a0 +#define ARCH_ID_AT91SAM9G45 0x819b05a0 +#define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */ +#define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */ +#define ARCH_ID_AT91CAP9 0x039A03A0 + +#define ARCH_ID_AT91SAM9XE128 0x329973a0 +#define ARCH_ID_AT91SAM9XE256 0x329a93a0 +#define ARCH_ID_AT91SAM9XE512 0x329aa3a0 + +#define ARCH_ID_AT572D940HF 0x0e0303e0 + +#define ARCH_ID_AT91M40800 0x14080044 +#define ARCH_ID_AT91R40807 0x44080746 +#define ARCH_ID_AT91M40807 0x14080745 +#define ARCH_ID_AT91R40008 0x44000840 + +static inline unsigned long at91_cpu_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION); +} + +static inline unsigned long at91_cpu_fully_identify(void) +{ + return at91_sys_read(AT91_DBGU_CIDR); +} + +#define ARCH_EXID_AT91SAM9M11 0x00000001 +#define ARCH_EXID_AT91SAM9M10 0x00000002 +#define ARCH_EXID_AT91SAM9G45 0x00000004 + +static inline unsigned long at91_exid_identify(void) +{ + return at91_sys_read(AT91_DBGU_EXID); +} + + +#define ARCH_FAMILY_AT91X92 0x09200000 +#define ARCH_FAMILY_AT91SAM9 0x01900000 +#define ARCH_FAMILY_AT91SAM9XE 0x02900000 + +static inline unsigned long at91_arch_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH); +} + +#ifdef CONFIG_ARCH_AT91CAP9 +#include <mach/at91_pmc.h> + +#define ARCH_REVISION_CAP9_B 0x399 +#define ARCH_REVISION_CAP9_C 0x601 + +static inline unsigned long at91cap9_rev_identify(void) +{ + return (at91_sys_read(AT91_PMC_VER)); +} +#endif + +#ifdef CONFIG_ARCH_AT91RM9200 +#define cpu_is_at91rm9200() (at91_cpu_identify() == ARCH_ID_AT91RM9200) +#else +#define cpu_is_at91rm9200() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9260 +#define cpu_is_at91sam9xe() (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE) +#define cpu_is_at91sam9260() ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe()) +#else +#define cpu_is_at91sam9xe() (0) +#define cpu_is_at91sam9260() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G20 +#define cpu_is_at91sam9g20() (at91_cpu_identify() == ARCH_ID_AT91SAM9G20) +#else +#define cpu_is_at91sam9g20() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9261 +#define cpu_is_at91sam9261() (at91_cpu_identify() == ARCH_ID_AT91SAM9261) +#else +#define cpu_is_at91sam9261() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G10 +#define cpu_is_at91sam9g10() ((at91_cpu_identify() & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) +#else +#define cpu_is_at91sam9g10() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9263 +#define cpu_is_at91sam9263() (at91_cpu_identify() == ARCH_ID_AT91SAM9263) +#else +#define cpu_is_at91sam9263() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9RL +#define cpu_is_at91sam9rl() (at91_cpu_identify() == ARCH_ID_AT91SAM9RL64) +#else +#define cpu_is_at91sam9rl() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G45 +#define cpu_is_at91sam9g45() (at91_cpu_identify() == ARCH_ID_AT91SAM9G45) +#define cpu_is_at91sam9g45es() (at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES) +#else +#define cpu_is_at91sam9g45() (0) +#define cpu_is_at91sam9g45es() (0) +#endif + +#ifdef CONFIG_ARCH_AT91CAP9 +#define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) +#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) +#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C) +#else +#define cpu_is_at91cap9() (0) +#define cpu_is_at91cap9_revB() (0) +#define cpu_is_at91cap9_revC() (0) +#endif + +#ifdef CONFIG_ARCH_AT572D940HF +#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF) +#else +#define cpu_is_at572d940hf() (0) +#endif + +/* + * Since this is ARM, we will never run on any AVR32 CPU. But these + * definitions may reduce clutter in common drivers. + */ +#define cpu_is_at32ap7000() (0) + +#endif diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h index 76d53ba..7e1a9a8 100644 --- a/arch/arm/mach-at91/include/mach/gpio.h +++ b/arch/arm/mach-at91/include/mach/gpio.h @@ -241,6 +241,7 @@ struct at91_gpio_bank { struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */ unsigned short id; /* peripheral ID */ unsigned long offset; /* offset from system peripheral base */ + struct clk *clock; }; extern int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 4feeed0..6864119 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -48,7 +48,7 @@ #include <errno.h> #include <asm/io.h> #include <mach/board.h> -#include <mach/clk.h> +#include <linux/clk.h> #include "macb.h" @@ -412,6 +412,9 @@ static int macb_probe(struct device_d *dev) unsigned long macb_hz; u32 ncfgr; struct at91_ether_platform_data *pdata; +#if defined(CONFIG_ARCH_AT91) + struct clk *pclk; +#endif if (!dev->platform_data) { printf("macb: no platform_data\n"); @@ -450,7 +453,13 @@ static int macb_probe(struct device_d *dev) * Do some basic initialization so that we at least can talk * to the PHY */ +#if defined(CONFIG_ARCH_AT91) + pclk = clk_get(dev, "macb_clk"); + clk_enable(pclk); + macb_hz = clk_get_rate(pclk); +#else macb_hz = get_macb_pclk_rate(0); +#endif if (macb_hz < 20000000) ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); else if (macb_hz < 40000000) diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c index e9e8116..b99ec4d 100644 --- a/drivers/serial/atmel.c +++ b/drivers/serial/atmel.c @@ -22,7 +22,7 @@ #include <init.h> #include <malloc.h> #include <asm/io.h> -#include <mach/clk.h> +#include <linux/clk.h> /* USART3 register offsets */ #define USART3_CR 0x0000 @@ -309,6 +309,21 @@ << USART3_##name##_OFFSET)) \ | USART3_BF(name,value)) +/* + * We wrap our port structure around the generic console_device. + */ +struct atmel_uart_port { + struct console_device uart; /* uart */ + struct clk *clk; /* uart clock */ + u32 uartclk; +}; + +static inline struct atmel_uart_port * +to_atmel_uart_port(struct console_device *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + static void atmel_serial_putc(struct console_device *cdev, char c) { struct device_d *dev = cdev->dev; @@ -336,16 +351,15 @@ static int atmel_serial_getc(struct console_device *cdev) static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); unsigned long divisor; - unsigned long usart_hz; /* * Master Clock * Baud Rate = -------------- * 16 * CD */ - usart_hz = get_usart_clk_rate(0); - divisor = (usart_hz / 16 + baudrate / 2) / baudrate; + divisor = (uart->uartclk / 16 + baudrate / 2) / baudrate; writel(USART3_BF(CD, divisor), dev->map_base + USART3_BRGR); return 0; @@ -359,6 +373,11 @@ static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) static int atmel_serial_init_port(struct console_device *cdev) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); + + uart->clk = clk_get(dev, "usart"); + clk_enable(uart->clk); + uart->uartclk = clk_get_rate(uart->clk); writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), dev->map_base + USART3_CR); @@ -376,9 +395,12 @@ static int atmel_serial_init_port(struct console_device *cdev) static int atmel_serial_probe(struct device_d *dev) { + struct atmel_uart_port *uart; struct console_device *cdev; - cdev = malloc(sizeof(struct console_device)); + uart = malloc(sizeof(struct atmel_uart_port)); + + cdev = &uart->uart; dev->type_data = cdev; cdev->dev = dev; cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/3 v2] at91: implement clock framework 2010-08-04 1:33 ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04 5:20 ` Baruch Siach 2010-08-04 6:06 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-04 6:12 ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 1 reply; 11+ messages in thread From: Baruch Siach @ 2010-08-04 5:20 UTC (permalink / raw) To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox Hi Jean-Christophe, On Wed, Aug 04, 2010 at 03:33:15AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote: > this implementation is based on linux one (v2.6.35-rc5-76-gd0c6f62) > it will calculate all the clock dynamically instead of statictly > this will use also the new clock framework > > it will also print the clock status after the console init > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > --- > v2: > upadate against mainline kernel > and add ref on which revision it's based on [snip] > diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h > index 1133b8f..422ac09 100644 > --- a/arch/arm/boards/mmccpu/config.h > +++ b/arch/arm/boards/mmccpu/config.h > @@ -1,7 +1,7 @@ > #ifndef __CONFIG_H > #define __CONFIG_H > > -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ > +#define AT91_M1IN_CLOCK 18432000 s/M1IN/MAIN/ ? baruch -- ~. .~ Tk Open Systems =}------------------------------------------------ooO--U--Ooo------------{= - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il - _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 3/3 v2] at91: implement clock framework 2010-08-04 5:20 ` Baruch Siach @ 2010-08-04 6:06 ` Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 0 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04 6:06 UTC (permalink / raw) To: Baruch Siach; +Cc: barebox On 08:20 Wed 04 Aug , Baruch Siach wrote: > Hi Jean-Christophe, > > On Wed, Aug 04, 2010 at 03:33:15AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote: > > this implementation is based on linux one (v2.6.35-rc5-76-gd0c6f62) > > it will calculate all the clock dynamically instead of statictly > > this will use also the new clock framework > > > > it will also print the clock status after the console init > > > > Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> > > --- > > v2: > > upadate against mainline kernel > > and add ref on which revision it's based on > > [snip] > > > diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h > > index 1133b8f..422ac09 100644 > > --- a/arch/arm/boards/mmccpu/config.h > > +++ b/arch/arm/boards/mmccpu/config.h > > @@ -1,7 +1,7 @@ > > #ifndef __CONFIG_H > > #define __CONFIG_H > > > > -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ > > +#define AT91_M1IN_CLOCK 18432000 > > s/M1IN/MAIN/ ? nice Best Regards, J. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/3 v3] at91: implement clock framework 2010-08-04 1:33 ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD 2010-08-04 5:20 ` Baruch Siach @ 2010-08-04 6:12 ` Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 0 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04 6:12 UTC (permalink / raw) To: barebox this implementation is based on linux one (v2.6.35-rc5-76-gd0c6f62) it will calculate all the clock dynamically instead of statictly this will use also the new clock framework it will also print the clock status after the console init Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- v3: fix typo Best Regards, J. arch/arm/boards/at91sam9260ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/config.h | 2 +- arch/arm/boards/at91sam9263ek/init.c | 3 - arch/arm/boards/mmccpu/config.h | 2 +- arch/arm/boards/mmccpu/init.c | 3 - arch/arm/boards/pm9263/config.h | 2 +- arch/arm/boards/pm9263/init.c | 3 - arch/arm/mach-at91/Makefile | 2 +- arch/arm/mach-at91/at91sam9260.c | 207 ++++++++ arch/arm/mach-at91/at91sam9260_devices.c | 18 +- arch/arm/mach-at91/at91sam9263.c | 217 ++++++++ arch/arm/mach-at91/at91sam9263_devices.c | 13 +- arch/arm/mach-at91/clock.c | 718 +++++++++++++++++++++++++++ arch/arm/mach-at91/clock.h | 31 ++ arch/arm/mach-at91/generic.h | 14 + arch/arm/mach-at91/gpio.c | 3 + arch/arm/mach-at91/include/mach/at91_dbgu.h | 66 +++ arch/arm/mach-at91/include/mach/clk.h | 39 -- arch/arm/mach-at91/include/mach/cpu.h | 158 ++++++ arch/arm/mach-at91/include/mach/gpio.h | 1 + drivers/net/macb.c | 11 +- drivers/serial/atmel.c | 32 +- 22 files changed, 1472 insertions(+), 75 deletions(-) create mode 100644 arch/arm/mach-at91/clock.c create mode 100644 arch/arm/mach-at91/clock.h create mode 100644 arch/arm/mach-at91/generic.h create mode 100644 arch/arm/mach-at91/include/mach/at91_dbgu.h delete mode 100644 arch/arm/mach-at91/include/mach/clk.h create mode 100644 arch/arm/mach-at91/include/mach/cpu.h diff --git a/arch/arm/boards/at91sam9260ek/config.h b/arch/arm/boards/at91sam9260ek/config.h index afd8563..006820c 100644 --- a/arch/arm/boards/at91sam9260ek/config.h +++ b/arch/arm/boards/at91sam9260ek/config.h @@ -1,6 +1,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 /* 18.432 MHz crystal */ #endif /* __CONFIG_H */ diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h index 9cc8af2..bc33227 100644 --- a/arch/arm/boards/at91sam9263ek/config.h +++ b/arch/arm/boards/at91sam9263ek/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 100000000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 16367660 /* 16.367 MHz crystal */ #define MASTER_PLL_MUL 171 #define MASTER_PLL_DIV 14 diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c index 21803ca..61cd295 100644 --- a/arch/arm/boards/at91sam9263ek/init.c +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -108,9 +108,6 @@ static int at91sam9263ek_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); ek_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h index 1133b8f..c37d5eb 100644 --- a/arch/arm/boards/mmccpu/config.h +++ b/arch/arm/boards/mmccpu/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 /* values */ #define MASTER_PLL_MUL 54 diff --git a/arch/arm/boards/mmccpu/init.c b/arch/arm/boards/mmccpu/init.c index e010a83..9a7d930 100644 --- a/arch/arm/boards/mmccpu/init.c +++ b/arch/arm/boards/mmccpu/init.c @@ -58,9 +58,6 @@ static int mmccpu_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(128 * 1024 * 1024); at91_add_device_eth(&macb_pdata); register_device(&cfi_dev); diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h index 9a9c5cd..5252df2 100644 --- a/arch/arm/boards/pm9263/config.h +++ b/arch/arm/boards/pm9263/config.h @@ -1,7 +1,7 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ +#define AT91_MAIN_CLOCK 18432000 #define MASTER_PLL_DIV 6 #define MASTER_PLL_MUL 65 diff --git a/arch/arm/boards/pm9263/init.c b/arch/arm/boards/pm9263/init.c index 88b91ea..d5ed921 100644 --- a/arch/arm/boards/pm9263/init.c +++ b/arch/arm/boards/pm9263/init.c @@ -107,9 +107,6 @@ static int pm9263_devices_init(void) at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - at91_add_device_sdram(64 * 1024 * 1024); pm_add_device_nand(); at91_add_device_eth(&macb_pdata); diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile index c848919..0f55883 100644 --- a/arch/arm/mach-at91/Makefile +++ b/arch/arm/mach-at91/Makefile @@ -1,4 +1,4 @@ -obj-y += clocksource.o gpio.o +obj-y += clock.o clocksource.o gpio.o obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 1a6e356..30d1a6a 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -2,22 +2,229 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "generic.h" +#include "clock.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioC_clk = { + .name = "pioC_clk", + .pmc_mask = 1 << AT91SAM9260_ID_PIOC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk adc_clk = { + .name = "adc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ADC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc_clk = { + .name = "mci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_MCI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc_clk = { + .name = "ssc_clk", + .pmc_mask = 1 << AT91SAM9260_ID_SSC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc0_clk = { + .name = "tc0_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc1_clk = { + .name = "tc1_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc2_clk = { + .name = "tc2_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9260_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9260_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9260_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart3_clk = { + .name = "usart3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart4_clk = { + .name = "usart4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart5_clk = { + .name = "usart5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_US5, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc3_clk = { + .name = "tc3_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC3, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc4_clk = { + .name = "tc4_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC4, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tc5_clk = { + .name = "tc5_clk", + .pmc_mask = 1 << AT91SAM9260_ID_TC5, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioC_clk, + &adc_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc_clk, + &udc_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc_clk, + &tc0_clk, + &tc1_clk, + &tc2_clk, + &ohci_clk, + &macb_clk, + &isi_clk, + &usart3_clk, + &usart4_clk, + &usart5_clk, + &tc3_clk, + &tc4_clk, + &tc5_clk, + // irq0 .. irq2 +}; + +/* + * The two programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; + +static void __init at91sam9260_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9260_gpio[] = { { .id = AT91SAM9260_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9260_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9260_ID_PIOC, .offset = AT91_PIOC, + .clock = &pioC_clk, } }; static int at91sam9260_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9260_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9260_gpio, 3); return 0; diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 0cfe913..398a721 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data sram_pdata = { .name = "sram0", .flags = DEVFS_RDWR, @@ -107,8 +109,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -233,37 +233,37 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9260_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9260_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9260_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; case AT91SAM9260_ID_US3: configure_usart3_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US3); + at91_clock_associate("usart3_clk", &uart3_serial_device, "usart"); register_device(&uart3_serial_device); break; case AT91SAM9260_ID_US4: configure_usart4_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US4); + at91_clock_associate("usart4_clk", &uart4_serial_device, "usart"); register_device(&uart4_serial_device); break; case AT91SAM9260_ID_US5: configure_usart5_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US5); + at91_clock_associate("usart5_clk", &uart5_serial_device, "usart"); register_device(&uart5_serial_device); break; default: diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 472b619..b0e3193 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -2,28 +2,245 @@ #include <gpio.h> #include <init.h> #include <asm/hardware.h> +#include <mach/at91_pmc.h> + +#include "clock.h" +#include "generic.h" + +/* -------------------------------------------------------------------- + * Clocks + * -------------------------------------------------------------------- */ + +/* + * The peripheral clocks. + */ +static struct clk pioA_clk = { + .name = "pioA_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioB_clk = { + .name = "pioB_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pioCDE_clk = { + .name = "pioCDE_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PIOCDE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart0_clk = { + .name = "usart0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart1_clk = { + .name = "usart1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk usart2_clk = { + .name = "usart2_clk", + .pmc_mask = 1 << AT91SAM9263_ID_US2, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc0_clk = { + .name = "mci0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk mmc1_clk = { + .name = "mci1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_MCI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk can_clk = { + .name = "can_clk", + .pmc_mask = 1 << AT91SAM9263_ID_CAN, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twi_clk = { + .name = "twi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TWI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi0_clk = { + .name = "spi0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk spi1_clk = { + .name = "spi1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SPI1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc0_clk = { + .name = "ssc0_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC0, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ssc1_clk = { + .name = "ssc1_clk", + .pmc_mask = 1 << AT91SAM9263_ID_SSC1, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ac97_clk = { + .name = "ac97_clk", + .pmc_mask = 1 << AT91SAM9263_ID_AC97C, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk tcb_clk = { + .name = "tcb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_TCB, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk pwm_clk = { + .name = "pwm_clk", + .pmc_mask = 1 << AT91SAM9263_ID_PWMC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk macb_clk = { + .name = "macb_clk", + .pmc_mask = 1 << AT91SAM9263_ID_EMAC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk dma_clk = { + .name = "dma_clk", + .pmc_mask = 1 << AT91SAM9263_ID_DMA, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk twodge_clk = { + .name = "2dge_clk", + .pmc_mask = 1 << AT91SAM9263_ID_2DGE, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk udc_clk = { + .name = "udc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UDP, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk isi_clk = { + .name = "isi_clk", + .pmc_mask = 1 << AT91SAM9263_ID_ISI, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk lcdc_clk = { + .name = "lcdc_clk", + .pmc_mask = 1 << AT91SAM9263_ID_LCDC, + .type = CLK_TYPE_PERIPHERAL, +}; +static struct clk ohci_clk = { + .name = "ohci_clk", + .pmc_mask = 1 << AT91SAM9263_ID_UHP, + .type = CLK_TYPE_PERIPHERAL, +}; + +static struct clk *periph_clocks[] = { + &pioA_clk, + &pioB_clk, + &pioCDE_clk, + &usart0_clk, + &usart1_clk, + &usart2_clk, + &mmc0_clk, + &mmc1_clk, + &can_clk, + &twi_clk, + &spi0_clk, + &spi1_clk, + &ssc0_clk, + &ssc1_clk, + &ac97_clk, + &tcb_clk, + &pwm_clk, + &macb_clk, + &twodge_clk, + &udc_clk, + &isi_clk, + &lcdc_clk, + &dma_clk, + &ohci_clk, + // irq0 .. irq1 +}; + +/* + * The four programmable clocks. + * You must configure pin multiplexing to bring these signals out. + */ +static struct clk pck0 = { + .name = "pck0", + .pmc_mask = AT91_PMC_PCK0, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 0, +}; +static struct clk pck1 = { + .name = "pck1", + .pmc_mask = AT91_PMC_PCK1, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 1, +}; +static struct clk pck2 = { + .name = "pck2", + .pmc_mask = AT91_PMC_PCK2, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 2, +}; +static struct clk pck3 = { + .name = "pck3", + .pmc_mask = AT91_PMC_PCK3, + .type = CLK_TYPE_PROGRAMMABLE, + .id = 3, +}; + +static void __init at91sam9263_register_clocks(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(periph_clocks); i++) + clk_register(periph_clocks[i]); + + clk_register(&pck0); + clk_register(&pck1); + clk_register(&pck2); + clk_register(&pck3); +} + +/* -------------------------------------------------------------------- + * GPIO + * -------------------------------------------------------------------- */ static struct at91_gpio_bank at91sam9263_gpio[] = { { .id = AT91SAM9263_ID_PIOA, .offset = AT91_PIOA, + .clock = &pioA_clk, }, { .id = AT91SAM9263_ID_PIOB, .offset = AT91_PIOB, + .clock = &pioB_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOC, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOD, + .clock = &pioCDE_clk, }, { .id = AT91SAM9263_ID_PIOCDE, .offset = AT91_PIOE, + .clock = &pioCDE_clk, } }; static int at91sam9263_initialize(void) { + /* Init clock subsystem */ + at91_clock_init(AT91_MAIN_CLOCK); + + /* Register the processor-specific clocks */ + at91sam9263_register_clocks(); + /* Register GPIO subsystem */ at91_gpio_init(at91sam9263_gpio, 5); return 0; diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 50a6348..7ebc32c 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -18,6 +18,8 @@ #include <mach/gpio.h> #include <mach/io.h> +#include "generic.h" + static struct memory_platform_data ram_pdata = { .name = "ram0", .flags = DEVFS_RDWR, @@ -106,9 +108,6 @@ void at91_add_device_nand(struct atmel_nand_data *data) if (data->det_pin) at91_set_gpio_input(data->det_pin, 1); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_PIOA | - 1 << AT91SAM9263_ID_PIOCDE); - nand_dev.platform_data = data; register_device(&nand_dev); } @@ -184,22 +183,22 @@ void at91_register_uart(unsigned id, unsigned pins) switch (id) { case 0: /* DBGU */ configure_dbgu_pins(); - at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS); + at91_clock_associate("mck", &dbgu_serial_device, "usart"); register_device(&dbgu_serial_device); break; case AT91SAM9263_ID_US0: configure_usart0_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US0); + at91_clock_associate("usart0_clk", &uart0_serial_device, "usart"); register_device(&uart0_serial_device); break; case AT91SAM9263_ID_US1: configure_usart1_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US1); + at91_clock_associate("usart1_clk", &uart1_serial_device, "usart"); register_device(&uart1_serial_device); break; case AT91SAM9263_ID_US2: configure_usart2_pins(pins); - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US2); + at91_clock_associate("usart2_clk", &uart2_serial_device, "usart"); register_device(&uart2_serial_device); break; default: diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c new file mode 100644 index 0000000..6fd09d5 --- /dev/null +++ b/arch/arm/mach-at91/clock.c @@ -0,0 +1,718 @@ +/* + * linux/arch/arm/mach-at91/clock.c + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * + * 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. + */ + +#include <common.h> +#include <linux/list.h> +#include <errno.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <init.h> + +#include <mach/hardware.h> +#include <mach/io.h> +#include <mach/at91_pmc.h> +#include <mach/cpu.h> + +#include "clock.h" +#include "generic.h" + +/* + * There's a lot more which can be done with clocks, including cpufreq + * integration, slow clock mode support (for system suspend), letting + * PLLB be used at other rates (on boards that don't need USB), etc. + */ + +#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY) +#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE) +#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL) +#define clk_is_sys(x) ((x)->type & CLK_TYPE_SYSTEM) + + +/* + * Chips have some kind of clocks : group them by functionality + */ +#define cpu_has_utmi() ( cpu_is_at91cap9() \ + || cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45()) + +#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \ + || cpu_is_at91sam9g45()) + +#define cpu_has_300M_plla() (cpu_is_at91sam9g10()) + +#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) + +#define cpu_has_upll() (cpu_is_at91sam9g45()) + +/* USB host HS & FS */ +#define cpu_has_uhp() (!cpu_is_at91sam9rl()) + +/* USB device FS only */ +#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \ + || cpu_is_at91sam9g45())) + +static LIST_HEAD(clocks); + +static u32 at91_pllb_usb_init; + +/* + * Four primary clock sources: two crystal oscillators (32K, main), and + * two PLLs. PLLA usually runs the master clock; and PLLB must run at + * 48 MHz (unless no USB function clocks are needed). The main clock and + * both PLLs are turned off to run in "slow clock mode" (system suspend). + */ +static struct clk clk32k = { + .name = "clk32k", + .rate_hz = AT91_SLOW_CLOCK, + .users = 1, /* always on */ + .id = 0, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk main_clk = { + .name = "main", + .pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */ + .id = 1, + .type = CLK_TYPE_PRIMARY, +}; +static struct clk plla = { + .name = "plla", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */ + .id = 2, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pllb_mode(struct clk *clk, int is_on) +{ + u32 value; + + if (is_on) { + is_on = AT91_PMC_LOCKB; + value = at91_pllb_usb_init; + } else + value = 0; + + // REVISIT: Add work-around for AT91RM9200 Errata #26 ? + at91_sys_write(AT91_CKGR_PLLBR, value); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on); +} + +static struct clk pllb = { + .name = "pllb", + .parent = &main_clk, + .pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */ + .mode = pllb_mode, + .id = 3, + .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL, +}; + +static void pmc_sys_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_SCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask); +} + +static void pmc_uckr_mode(struct clk *clk, int is_on) +{ + unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR); + + if (cpu_is_at91sam9g45()) { + if (is_on) + uckr |= AT91_PMC_BIASEN; + else + uckr &= ~AT91_PMC_BIASEN; + } + + if (is_on) { + is_on = AT91_PMC_LOCKU; + at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask); + } else + at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask)); + + do { + barrier(); + } while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on); +} + +/* USB function clocks (PLLB must be 48 MHz) */ +static struct clk udpck = { + .name = "udpck", + .parent = &pllb, + .mode = pmc_sys_mode, +}; +static struct clk utmi_clk = { + .name = "utmi_clk", + .parent = &main_clk, + .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */ + .mode = pmc_uckr_mode, + .type = CLK_TYPE_PLL, +}; +static struct clk uhpck = { + .name = "uhpck", + /*.parent = ... we choose parent at runtime */ + .mode = pmc_sys_mode, +}; + + +/* + * The master clock is divided from the CPU clock (by 1-4). It's used for + * memory, interfaces to on-chip peripherals, the AIC, and sometimes more + * (e.g baud rate generation). It's sourced from one of the primary clocks. + */ +static struct clk mck = { + .name = "mck", + .pmc_mask = AT91_PMC_MCKRDY, /* in PMC_SR */ +}; + +static void pmc_periph_mode(struct clk *clk, int is_on) +{ + if (is_on) + at91_sys_write(AT91_PMC_PCER, clk->pmc_mask); + else + at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask); +} + +static struct clk *at91_css_to_clk(unsigned long css) +{ + switch (css) { + case AT91_PMC_CSS_SLOW: + return &clk32k; + case AT91_PMC_CSS_MAIN: + return &main_clk; + case AT91_PMC_CSS_PLLA: + return &plla; + case AT91_PMC_CSS_PLLB: + if (cpu_has_upll()) + /* CSS_PLLB == CSS_UPLL */ + return &utmi_clk; + else if (cpu_has_pllb()) + return &pllb; + } + + return NULL; +} + +/* + * Associate a particular clock with a function (eg, "uart") and device. + * The drivers can then request the same 'function' with several different + * devices and not care about which clock name to use. + */ +void at91_clock_associate(const char *id, struct device_d *dev, const char *func) +{ + struct clk *clk = clk_get(NULL, id); + + if (!dev || !clk || !IS_ERR(clk_get(dev, func))) + return; + + clk->function = func; + clk->dev = dev; +} + +/* clocks cannot be de-registered no refcounting necessary */ +struct clk *clk_get(struct device_d *dev, const char *id) +{ + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (strcmp(id, clk->name) == 0) + return clk; + if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0) + return clk; + } + + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL(clk_put); + +static void __clk_enable(struct clk *clk) +{ + if (clk->parent) + __clk_enable(clk->parent); + if (clk->users++ == 0 && clk->mode) + clk->mode(clk, 1); +} + +int clk_enable(struct clk *clk) +{ + __clk_enable(clk); + return 0; +} +EXPORT_SYMBOL(clk_enable); + +static void __clk_disable(struct clk *clk) +{ + BUG_ON(clk->users == 0); + if (--clk->users == 0 && clk->mode) + clk->mode(clk, 0); + if (clk->parent) + __clk_disable(clk->parent); +} + +void clk_disable(struct clk *clk) +{ + __clk_disable(clk); +} +EXPORT_SYMBOL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + unsigned long rate; + + for (;;) { + rate = clk->rate_hz; + if (rate || !clk->parent) + break; + clk = clk->parent; + } + return rate; +} +EXPORT_SYMBOL(clk_get_rate); + +/*------------------------------------------------------------------------*/ + +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + +/* + * For now, only the programmable clocks support reparenting (MCK could + * do this too, with care) or rate changing (the PLLs could do this too, + * ditto MCK but that's more for cpufreq). Drivers may reparent to get + * a better rate match; we don't. + */ + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + unsigned long prev = ULONG_MAX; + + if (!clk_is_programmable(clk)) + return -EINVAL; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual > rate) + prev = actual; + + if (actual && actual <= rate) { + if ((prev - rate) < (rate - actual)) { + actual = prev; + prescale--; + } + break; + } + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_round_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long flags; + unsigned prescale; + unsigned long actual; + + if (!clk_is_programmable(clk)) + return -EINVAL; + if (clk->users) + return -EBUSY; + + actual = clk->parent->rate_hz; + for (prescale = 0; prescale < 7; prescale++) { + if (actual && actual <= rate) { + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + pckr &= AT91_PMC_CSS; /* clock selection */ + pckr |= prescale << 2; + at91_sys_write(AT91_PMC_PCKR(clk->id), pckr); + clk->rate_hz = actual; + break; + } + actual >>= 1; + } + + return (prescale < 7) ? actual : -ENOENT; +} +EXPORT_SYMBOL(clk_set_rate); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL(clk_get_parent); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long flags; + + if (clk->users) + return -EBUSY; + if (!clk_is_primary(parent) || !clk_is_programmable(clk)) + return -EINVAL; + + if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB) + return -EINVAL; + + clk->rate_hz = parent->rate_hz; + clk->parent = parent; + at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id); + + return 0; +} +EXPORT_SYMBOL(clk_set_parent); + +/* establish PCK0..PCKN parentage and rate */ +static void init_programmable_clock(struct clk *clk) +{ + struct clk *parent; + u32 pckr; + + pckr = at91_sys_read(AT91_PMC_PCKR(clk->id)); + parent = at91_css_to_clk(pckr & AT91_PMC_CSS); + clk->parent = parent; + clk->rate_hz = parent->rate_hz / (1 << ((pckr & AT91_PMC_PRES) >> 2)); +} + +#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */ + +/*------------------------------------------------------------------------*/ + +/* Register a new clock */ +int clk_register(struct clk *clk) +{ + if (clk_is_peripheral(clk)) { + clk->parent = &mck; + clk->mode = pmc_periph_mode; + list_add_tail(&clk->node, &clocks); + } + else if (clk_is_sys(clk)) { + clk->parent = &mck; + clk->mode = pmc_sys_mode; + + list_add_tail(&clk->node, &clocks); + } +#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS + else if (clk_is_programmable(clk)) { + clk->mode = pmc_sys_mode; + init_programmable_clock(clk); + list_add_tail(&clk->node, &clocks); + } +#endif + + return 0; +} + + +/*------------------------------------------------------------------------*/ + +static u32 at91_pll_rate(struct clk *pll, u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + + return freq; +} + +static u32 at91_usb_rate(struct clk *pll, u32 freq, u32 reg) +{ + if (pll == &pllb && (reg & AT91_PMC_USB96M)) + return freq / 2; + else + return freq; +} + +static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + * Warning: some newer products need 2MHz min. + */ + input = main_freq / i; + if (cpu_is_at91sam9g20() && input < 2000000) + continue; + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; + if (cpu_is_at91sam9g20() && mul > 63) + continue; + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} + +static struct clk *const standard_pmc_clocks[] = { + /* four primary clocks */ + &clk32k, + &main_clk, + &plla, + + /* MCK */ + &mck +}; + +/* PLLB generated USB full speed clock init */ +static void at91_pllb_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + uhpck.parent = &pllb; + + at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M; + pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init); + if (cpu_is_at91rm9200()) { + uhpck.pmc_mask = AT91RM9200_PMC_UHP; + udpck.pmc_mask = AT91RM9200_PMC_UDP; + at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP); + } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || + cpu_is_at91sam9263() || cpu_is_at91sam9g20() || + cpu_is_at91sam9g10() || cpu_is_at572d940hf()) { + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + udpck.pmc_mask = AT91SAM926x_PMC_UDP; + } else if (cpu_is_at91cap9()) { + uhpck.pmc_mask = AT91CAP9_PMC_UHP; + } + at91_sys_write(AT91_CKGR_PLLBR, 0); + + udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); + uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init); +} + +/* UPLL generated USB full speed clock init */ +static void at91_upll_usbfs_clock_init(unsigned long main_clock) +{ + /* + * USB clock init: choose 480 MHz from UPLL, + */ + unsigned int usbr = AT91_PMC_USBS_UPLL; + + /* Setup divider by 10 to reach 48 MHz */ + usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV; + + at91_sys_write(AT91_PMC_USB, usbr); + + /* Now set uhpck values */ + uhpck.parent = &utmi_clk; + uhpck.pmc_mask = AT91SAM926x_PMC_UHP; + uhpck.rate_hz = utmi_clk.parent->rate_hz; + uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8); +} + +static int pll_overclock = 0; + +int at91_clock_init(unsigned long main_clock) +{ + unsigned tmp, freq, mckr; + int i; + + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = at91_sys_read(AT91_CKGR_MCFR); + } while (!(tmp & AT91_PMC_MAINRDY)); + main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16); + } + main_clk.rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR)); + if (cpu_has_300M_plla()) { + if (plla.rate_hz > 300000000) + pll_overclock = 1; + } else if (cpu_has_800M_plla()) { + if (plla.rate_hz > 800000000) + pll_overclock = 1; + } else { + if (plla.rate_hz > 209000000) + pll_overclock = 1; + } + + if (cpu_is_at91sam9g45()) { + mckr = at91_sys_read(AT91_PMC_MCKR); + plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */ + } + + if (!cpu_has_pllb() && cpu_has_upll()) { + /* setup UTMI clock as the fourth primary clock + * (instead of pllb) */ + utmi_clk.type |= CLK_TYPE_PRIMARY; + utmi_clk.id = 3; + } + + /* + * USB HS clock init + */ + if (cpu_has_utmi()) { + /* + * multiplier is hard-wired to 40 + * (obtain the USB High Speed 480 MHz when input is 12 MHz) + */ + utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz; + } + + /* + * USB FS clock init + */ + if (cpu_has_pllb()) + at91_pllb_usbfs_clock_init(main_clock); + if (cpu_has_upll()) + /* assumes that we choose UPLL for USB and not PLLA */ + at91_upll_usbfs_clock_init(main_clock); + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = at91_sys_read(AT91_PMC_MCKR); + mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS); + freq = mck.parent->rate_hz; + freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2)); /* prescale */ + if (cpu_is_at91rm9200()) { + mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else if (cpu_is_at91sam9g20()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) ? + freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + if (mckr & AT91_PMC_PDIV) + freq /= 2; /* processor clock division */ + } else if (cpu_is_at91sam9g45()) { + mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ? + freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } else { + mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */ + } + + /* Register the PMC's standard clocks */ + for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++) + list_add_tail(&standard_pmc_clocks[i]->node, &clocks); + + if (cpu_has_pllb()) + list_add_tail(&pllb.node, &clocks); + + if (cpu_has_uhp()) + list_add_tail(&uhpck.node, &clocks); + + if (cpu_has_udpfs()) + list_add_tail(&udpck.node, &clocks); + + if (cpu_has_utmi()) + list_add_tail(&utmi_clk.node, &clocks); + + /* MCK and CPU clock are "always on" */ + clk_enable(&mck); + + return 0; +} + +static int at91_clock_display(void) +{ + if (pll_overclock) + pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000); + + printf("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n", + mck.parent->rate_hz / 1000000, (unsigned) mck.rate_hz / 1000000, + (unsigned) main_clk.rate_hz / 1000000, + ((unsigned) main_clk.rate_hz % 1000000) / 1000); + + return 0; +} +postconsole_initcall(at91_clock_display); + +/* + * Several unused clocks may be active. Turn them off. + */ +static int at91_clock_reset(void) +{ + unsigned long pcdr = 0; + unsigned long scdr = 0; + struct clk *clk; + + list_for_each_entry(clk, &clocks, node) { + if (clk->users > 0) + continue; + + if (clk->mode == pmc_periph_mode) + pcdr |= clk->pmc_mask; + + if (clk->mode == pmc_sys_mode) + scdr |= clk->pmc_mask; + + pr_debug("Clocks: disable unused %s\n", clk->name); + } + + at91_sys_write(AT91_PMC_PCDR, pcdr); + at91_sys_write(AT91_PMC_SCDR, scdr); + + return 0; +} +late_initcall(at91_clock_reset); diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h new file mode 100644 index 0000000..c8ecd0c --- /dev/null +++ b/arch/arm/mach-at91/clock.h @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/mach-at91/clock.h + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#define CLK_TYPE_PRIMARY 0x1 +#define CLK_TYPE_PLL 0x2 +#define CLK_TYPE_PROGRAMMABLE 0x4 +#define CLK_TYPE_PERIPHERAL 0x8 +#define CLK_TYPE_SYSTEM 0x10 + + +struct clk { + struct list_head node; + const char *name; /* unique clock name */ + const char *function; /* function of the clock */ + struct device_d *dev; /* device associated with function */ + unsigned long rate_hz; + struct clk *parent; + u32 pmc_mask; + void (*mode)(struct clk *, int); + unsigned id:3; /* PCK0..4, or 32k/main/a/b */ + unsigned type; /* clock type */ + u16 users; +}; + + +extern int __init clk_register(struct clk *clk); diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h new file mode 100644 index 0000000..b3a029d --- /dev/null +++ b/arch/arm/mach-at91/generic.h @@ -0,0 +1,14 @@ +/* + * linux/arch/arm/mach-at91/generic.h + * + * Copyright (C) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + /* Clocks */ +extern int __init at91_clock_init(unsigned long main_clock); +struct device_d; +extern void __init at91_clock_associate(const char *id, struct device_d *dev, const char *func); diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index 1cafaf7..b257128 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -22,6 +22,7 @@ */ #include <common.h> +#include <linux/clk.h> #include <errno.h> #include <asm/io.h> #include <mach/gpio.h> @@ -245,6 +246,8 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) data->regbase = data->offset + (void __iomem *)AT91_BASE_SYS; + /* enable PIO controller's clock */ + clk_enable(data->clock); /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ if (last && last->id == data->id) diff --git a/arch/arm/mach-at91/include/mach/at91_dbgu.h b/arch/arm/mach-at91/include/mach/at91_dbgu.h new file mode 100644 index 0000000..6dcaa77 --- /dev/null +++ b/arch/arm/mach-at91/include/mach/at91_dbgu.h @@ -0,0 +1,66 @@ +/* + * arch/arm/mach-at91/include/mach/at91_dbgu.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Debug Unit (DBGU) - System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * 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. + */ + +#ifndef AT91_DBGU_H +#define AT91_DBGU_H + +#ifdef AT91_DBGU +#define AT91_DBGU_CR (AT91_DBGU + 0x00) /* Control Register */ +#define AT91_DBGU_MR (AT91_DBGU + 0x04) /* Mode Register */ +#define AT91_DBGU_IER (AT91_DBGU + 0x08) /* Interrupt Enable Register */ +#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */ +#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */ +#define AT91_DBGU_IDR (AT91_DBGU + 0x0c) /* Interrupt Disable Register */ +#define AT91_DBGU_IMR (AT91_DBGU + 0x10) /* Interrupt Mask Register */ +#define AT91_DBGU_SR (AT91_DBGU + 0x14) /* Status Register */ +#define AT91_DBGU_RHR (AT91_DBGU + 0x18) /* Receiver Holding Register */ +#define AT91_DBGU_THR (AT91_DBGU + 0x1c) /* Transmitter Holding Register */ +#define AT91_DBGU_BRGR (AT91_DBGU + 0x20) /* Baud Rate Generator Register */ + +#define AT91_DBGU_CIDR (AT91_DBGU + 0x40) /* Chip ID Register */ +#define AT91_DBGU_EXID (AT91_DBGU + 0x44) /* Chip ID Extension Register */ +#define AT91_DBGU_FNR (AT91_DBGU + 0x48) /* Force NTRST Register [SAM9 only] */ +#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */ + +#endif /* AT91_DBGU */ + +/* + * Some AT91 parts that don't have full DEBUG units still support the ID + * and extensions register. + */ +#define AT91_CIDR_VERSION (0x1f << 0) /* Version of the Device */ +#define AT91_CIDR_EPROC (7 << 5) /* Embedded Processor */ +#define AT91_CIDR_NVPSIZ (0xf << 8) /* Nonvolatile Program Memory Size */ +#define AT91_CIDR_NVPSIZ2 (0xf << 12) /* Second Nonvolatile Program Memory Size */ +#define AT91_CIDR_SRAMSIZ (0xf << 16) /* Internal SRAM Size */ +#define AT91_CIDR_SRAMSIZ_1K (1 << 16) +#define AT91_CIDR_SRAMSIZ_2K (2 << 16) +#define AT91_CIDR_SRAMSIZ_112K (4 << 16) +#define AT91_CIDR_SRAMSIZ_4K (5 << 16) +#define AT91_CIDR_SRAMSIZ_80K (6 << 16) +#define AT91_CIDR_SRAMSIZ_160K (7 << 16) +#define AT91_CIDR_SRAMSIZ_8K (8 << 16) +#define AT91_CIDR_SRAMSIZ_16K (9 << 16) +#define AT91_CIDR_SRAMSIZ_32K (10 << 16) +#define AT91_CIDR_SRAMSIZ_64K (11 << 16) +#define AT91_CIDR_SRAMSIZ_128K (12 << 16) +#define AT91_CIDR_SRAMSIZ_256K (13 << 16) +#define AT91_CIDR_SRAMSIZ_96K (14 << 16) +#define AT91_CIDR_SRAMSIZ_512K (15 << 16) +#define AT91_CIDR_ARCH (0xff << 20) /* Architecture Identifier */ +#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */ +#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */ + +#endif diff --git a/arch/arm/mach-at91/include/mach/clk.h b/arch/arm/mach-at91/include/mach/clk.h deleted file mode 100644 index a9c0683..0000000 --- a/arch/arm/mach-at91/include/mach/clk.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * (C) Copyright 2007 - * Stelian Pop <stelian.pop@leadtechdesign.com> - * Lead Tech Design <www.leadtechdesign.com> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * 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., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#ifndef __ASM_ARM_ARCH_CLK_H__ -#define __ASM_ARM_ARCH_CLK_H__ - -#include <mach/hardware.h> - -static inline unsigned long get_macb_pclk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -static inline unsigned long get_usart_clk_rate(unsigned int dev_id) -{ - return AT91_MASTER_CLOCK; -} - -#endif /* __ASM_ARM_ARCH_CLK_H__ */ diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h new file mode 100644 index 0000000..833659d --- /dev/null +++ b/arch/arm/mach-at91/include/mach/cpu.h @@ -0,0 +1,158 @@ +/* + * arch/arm/mach-at91/include/mach/cpu.h + * + * Copyright (C) 2006 SAN People + * + * 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. + * + */ + +#ifndef __ASM_ARCH_CPU_H +#define __ASM_ARCH_CPU_H + +#include <mach/hardware.h> +#include <mach/at91_dbgu.h> + + +#define ARCH_ID_AT91RM9200 0x09290780 +#define ARCH_ID_AT91SAM9260 0x019803a0 +#define ARCH_ID_AT91SAM9261 0x019703a0 +#define ARCH_ID_AT91SAM9263 0x019607a0 +#define ARCH_ID_AT91SAM9G10 0x019903a0 +#define ARCH_ID_AT91SAM9G20 0x019905a0 +#define ARCH_ID_AT91SAM9RL64 0x019b03a0 +#define ARCH_ID_AT91SAM9G45 0x819b05a0 +#define ARCH_ID_AT91SAM9G45MRL 0x819b05a2 /* aka 9G45-ES2 & non ES lots */ +#define ARCH_ID_AT91SAM9G45ES 0x819b05a1 /* 9G45-ES (Engineering Sample) */ +#define ARCH_ID_AT91CAP9 0x039A03A0 + +#define ARCH_ID_AT91SAM9XE128 0x329973a0 +#define ARCH_ID_AT91SAM9XE256 0x329a93a0 +#define ARCH_ID_AT91SAM9XE512 0x329aa3a0 + +#define ARCH_ID_AT572D940HF 0x0e0303e0 + +#define ARCH_ID_AT91M40800 0x14080044 +#define ARCH_ID_AT91R40807 0x44080746 +#define ARCH_ID_AT91M40807 0x14080745 +#define ARCH_ID_AT91R40008 0x44000840 + +static inline unsigned long at91_cpu_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION); +} + +static inline unsigned long at91_cpu_fully_identify(void) +{ + return at91_sys_read(AT91_DBGU_CIDR); +} + +#define ARCH_EXID_AT91SAM9M11 0x00000001 +#define ARCH_EXID_AT91SAM9M10 0x00000002 +#define ARCH_EXID_AT91SAM9G45 0x00000004 + +static inline unsigned long at91_exid_identify(void) +{ + return at91_sys_read(AT91_DBGU_EXID); +} + + +#define ARCH_FAMILY_AT91X92 0x09200000 +#define ARCH_FAMILY_AT91SAM9 0x01900000 +#define ARCH_FAMILY_AT91SAM9XE 0x02900000 + +static inline unsigned long at91_arch_identify(void) +{ + return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH); +} + +#ifdef CONFIG_ARCH_AT91CAP9 +#include <mach/at91_pmc.h> + +#define ARCH_REVISION_CAP9_B 0x399 +#define ARCH_REVISION_CAP9_C 0x601 + +static inline unsigned long at91cap9_rev_identify(void) +{ + return (at91_sys_read(AT91_PMC_VER)); +} +#endif + +#ifdef CONFIG_ARCH_AT91RM9200 +#define cpu_is_at91rm9200() (at91_cpu_identify() == ARCH_ID_AT91RM9200) +#else +#define cpu_is_at91rm9200() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9260 +#define cpu_is_at91sam9xe() (at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE) +#define cpu_is_at91sam9260() ((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe()) +#else +#define cpu_is_at91sam9xe() (0) +#define cpu_is_at91sam9260() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G20 +#define cpu_is_at91sam9g20() (at91_cpu_identify() == ARCH_ID_AT91SAM9G20) +#else +#define cpu_is_at91sam9g20() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9261 +#define cpu_is_at91sam9261() (at91_cpu_identify() == ARCH_ID_AT91SAM9261) +#else +#define cpu_is_at91sam9261() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G10 +#define cpu_is_at91sam9g10() ((at91_cpu_identify() & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) +#else +#define cpu_is_at91sam9g10() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9263 +#define cpu_is_at91sam9263() (at91_cpu_identify() == ARCH_ID_AT91SAM9263) +#else +#define cpu_is_at91sam9263() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9RL +#define cpu_is_at91sam9rl() (at91_cpu_identify() == ARCH_ID_AT91SAM9RL64) +#else +#define cpu_is_at91sam9rl() (0) +#endif + +#ifdef CONFIG_ARCH_AT91SAM9G45 +#define cpu_is_at91sam9g45() (at91_cpu_identify() == ARCH_ID_AT91SAM9G45) +#define cpu_is_at91sam9g45es() (at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES) +#else +#define cpu_is_at91sam9g45() (0) +#define cpu_is_at91sam9g45es() (0) +#endif + +#ifdef CONFIG_ARCH_AT91CAP9 +#define cpu_is_at91cap9() (at91_cpu_identify() == ARCH_ID_AT91CAP9) +#define cpu_is_at91cap9_revB() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_B) +#define cpu_is_at91cap9_revC() (at91cap9_rev_identify() == ARCH_REVISION_CAP9_C) +#else +#define cpu_is_at91cap9() (0) +#define cpu_is_at91cap9_revB() (0) +#define cpu_is_at91cap9_revC() (0) +#endif + +#ifdef CONFIG_ARCH_AT572D940HF +#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF) +#else +#define cpu_is_at572d940hf() (0) +#endif + +/* + * Since this is ARM, we will never run on any AVR32 CPU. But these + * definitions may reduce clutter in common drivers. + */ +#define cpu_is_at32ap7000() (0) + +#endif diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h index 76d53ba..7e1a9a8 100644 --- a/arch/arm/mach-at91/include/mach/gpio.h +++ b/arch/arm/mach-at91/include/mach/gpio.h @@ -241,6 +241,7 @@ struct at91_gpio_bank { struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */ unsigned short id; /* peripheral ID */ unsigned long offset; /* offset from system peripheral base */ + struct clk *clock; }; extern int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks); diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 4feeed0..6864119 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -48,7 +48,7 @@ #include <errno.h> #include <asm/io.h> #include <mach/board.h> -#include <mach/clk.h> +#include <linux/clk.h> #include "macb.h" @@ -412,6 +412,9 @@ static int macb_probe(struct device_d *dev) unsigned long macb_hz; u32 ncfgr; struct at91_ether_platform_data *pdata; +#if defined(CONFIG_ARCH_AT91) + struct clk *pclk; +#endif if (!dev->platform_data) { printf("macb: no platform_data\n"); @@ -450,7 +453,13 @@ static int macb_probe(struct device_d *dev) * Do some basic initialization so that we at least can talk * to the PHY */ +#if defined(CONFIG_ARCH_AT91) + pclk = clk_get(dev, "macb_clk"); + clk_enable(pclk); + macb_hz = clk_get_rate(pclk); +#else macb_hz = get_macb_pclk_rate(0); +#endif if (macb_hz < 20000000) ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); else if (macb_hz < 40000000) diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c index e9e8116..b99ec4d 100644 --- a/drivers/serial/atmel.c +++ b/drivers/serial/atmel.c @@ -22,7 +22,7 @@ #include <init.h> #include <malloc.h> #include <asm/io.h> -#include <mach/clk.h> +#include <linux/clk.h> /* USART3 register offsets */ #define USART3_CR 0x0000 @@ -309,6 +309,21 @@ << USART3_##name##_OFFSET)) \ | USART3_BF(name,value)) +/* + * We wrap our port structure around the generic console_device. + */ +struct atmel_uart_port { + struct console_device uart; /* uart */ + struct clk *clk; /* uart clock */ + u32 uartclk; +}; + +static inline struct atmel_uart_port * +to_atmel_uart_port(struct console_device *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + static void atmel_serial_putc(struct console_device *cdev, char c) { struct device_d *dev = cdev->dev; @@ -336,16 +351,15 @@ static int atmel_serial_getc(struct console_device *cdev) static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); unsigned long divisor; - unsigned long usart_hz; /* * Master Clock * Baud Rate = -------------- * 16 * CD */ - usart_hz = get_usart_clk_rate(0); - divisor = (usart_hz / 16 + baudrate / 2) / baudrate; + divisor = (uart->uartclk / 16 + baudrate / 2) / baudrate; writel(USART3_BF(CD, divisor), dev->map_base + USART3_BRGR); return 0; @@ -359,6 +373,11 @@ static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate) static int atmel_serial_init_port(struct console_device *cdev) { struct device_d *dev = cdev->dev; + struct atmel_uart_port *uart = to_atmel_uart_port(cdev); + + uart->clk = clk_get(dev, "usart"); + clk_enable(uart->clk); + uart->uartclk = clk_get_rate(uart->clk); writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), dev->map_base + USART3_CR); @@ -376,9 +395,12 @@ static int atmel_serial_init_port(struct console_device *cdev) static int atmel_serial_probe(struct device_d *dev) { + struct atmel_uart_port *uart; struct console_device *cdev; - cdev = malloc(sizeof(struct console_device)); + uart = malloc(sizeof(struct atmel_uart_port)); + + cdev = &uart->uart; dev->type_data = cdev; cdev->dev = dev; cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V2] initcall: add postconsole_initcall 2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-29 16:53 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-30 1:21 ` [PATCH V3] " Jean-Christophe PLAGNIOL-VILLARD 1 sibling, 1 reply; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-29 16:53 UTC (permalink / raw) To: barebox this will allow us to print information as soon as the console will be enable Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- HI, this patch is a rebase version which is needed by at91 since the switch to linux clk framework which was forget Best Regards, J. include/init.h | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/init.h b/include/init.h index bc70874..9651f2a 100644 --- a/include/init.h +++ b/include/init.h @@ -25,10 +25,11 @@ typedef int (*initcall_t)(void); #define core_initcall(fn) __define_initcall("1",fn,1) #define postcore_initcall(fn) __define_initcall("2",fn,2) #define console_initcall(fn) __define_initcall("3",fn,3) -#define coredevice_initcall(fn) __define_initcall("4",fn,4) -#define fs_initcall(fn) __define_initcall("5",fn,5) -#define device_initcall(fn) __define_initcall("6",fn,6) -#define late_initcall(fn) __define_initcall("7",fn,7) +#define postconsole_initcall(fn) __define_initcall("4",fn,4) +#define coredevice_initcall(fn) __define_initcall("5",fn,5) +#define fs_initcall(fn) __define_initcall("6",fn,6) +#define device_initcall(fn) __define_initcall("7",fn,7) +#define late_initcall(fn) __define_initcall("8",fn,8) /* section for code used very early when * - we're not running from where we linked at -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH V3] initcall: add postconsole_initcall 2010-08-29 16:53 ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-30 1:21 ` Jean-Christophe PLAGNIOL-VILLARD 0 siblings, 0 replies; 11+ messages in thread From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-30 1:21 UTC (permalink / raw) To: barebox this will allow us to print information as soon as the console will be enable Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> --- HI, this patch is a rebase version which is needed by at91 since the switch to linux clk framework which was forget v3: add missing KEEP for linker script Best Regards, J. include/asm-generic/barebox.lds.h | 3 ++- include/init.h | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h index 99ccc5e..1d3f4f7 100644 --- a/include/asm-generic/barebox.lds.h +++ b/include/asm-generic/barebox.lds.h @@ -15,7 +15,8 @@ KEEP(*(.initcall.4)) \ KEEP(*(.initcall.5)) \ KEEP(*(.initcall.6)) \ - KEEP(*(.initcall.7)) + KEEP(*(.initcall.7)) \ + KEEP(*(.initcall.8)) #define BAREBOX_CMDS KEEP(*(SORT_BY_NAME(.barebox_cmd*))) diff --git a/include/init.h b/include/init.h index bc70874..8692b68 100644 --- a/include/init.h +++ b/include/init.h @@ -25,10 +25,11 @@ typedef int (*initcall_t)(void); #define core_initcall(fn) __define_initcall("1",fn,1) #define postcore_initcall(fn) __define_initcall("2",fn,2) #define console_initcall(fn) __define_initcall("3",fn,3) -#define coredevice_initcall(fn) __define_initcall("4",fn,4) -#define fs_initcall(fn) __define_initcall("5",fn,5) -#define device_initcall(fn) __define_initcall("6",fn,6) -#define late_initcall(fn) __define_initcall("7",fn,7) +#define postconsole_initcall(fn) __define_initcall("4",fn,4) +#define coredevice_initcall(fn) __define_initcall("5",fn,5) +#define fs_initcall(fn) __define_initcall("6",fn,6) +#define device_initcall(fn) __define_initcall("7",fn,7) +#define late_initcall(fn) __define_initcall("8",fn,8) /* section for code used very early when * - we're not running from where we linked at -- 1.7.1 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2010-08-30 1:22 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2010-08-03 12:51 [PATCH 0/3] introduce clk framework Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 12:53 ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD 2010-08-03 20:23 ` Sascha Hauer 2010-08-04 1:33 ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD 2010-08-04 5:20 ` Baruch Siach 2010-08-04 6:06 ` Jean-Christophe PLAGNIOL-VILLARD 2010-08-04 6:12 ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD 2010-08-29 16:53 ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD 2010-08-30 1:21 ` [PATCH V3] " Jean-Christophe PLAGNIOL-VILLARD
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox