diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 763a005..447a2c1 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -26,7 +26,7 @@ menu "i.MX specific settings " config IMX_CLKO bool "clko command" - depends on ARCH_IMX27 + depends on ARCH_IMX27 || ARCH_IMX35 help The i.MX SoCs have a Pin which can output different reference frequencies. Say y here if you want to have the clko command which lets you select the diff --git a/arch/arm/mach-imx/clko.c b/arch/arm/mach-imx/clko.c index 4eaf369..bee1ce2 100644 --- a/arch/arm/mach-imx/clko.c +++ b/arch/arm/mach-imx/clko.c @@ -2,10 +2,11 @@ #include #include #include +#include static int do_clko (cmd_tbl_t *cmdtp, int argc, char *argv[]) { - int opt, div = 0, src = -2; + int opt, div = 0, src = -2, ret; getopt_reset(); @@ -26,33 +27,26 @@ } if (src == -1) { - PCDR0 &= ~(1 << 25); + imx_clko_set_src(-1); return 0; } - if (src != -2) { - ulong ccsr; - ccsr = CCSR & ~0x1f; - ccsr |= src & 0x1f; - CCSR = ccsr; - } + if (src != -2) + imx_clko_set_src(src); if (div != 0) { - ulong pcdr; - div--; - pcdr = PCDR0 & ~(7 << 22); - pcdr |= (div & 0x7) << 22; - PCDR0 = pcdr; + ret = imx_clko_set_div(div); + if (ret != div) + printf("limited divider to %d\n", ret); } - PCDR0 |= (1 << 25); return 0; } static __maybe_unused char cmd_clko_help[] = "Usage: clko [OPTION]...\n" "Route different signals to the i.MX clko pin\n" -" -d
Divider (1..8)\n" +" -d
Divider\n" " -s Clock select. See Ref. Manual for valid sources. Use -1\n" " for disabling clock output\n"; @@ -63,3 +57,38 @@ U_BOOT_CMD_HELP(cmd_clko_help) U_BOOT_CMD_END + +static int do_mcpy_test (cmd_tbl_t *cmdtp, int argc, char *argv[]) +{ + unsigned long src, dest, count, end; + + if (argc < 4) + return 1; + + dest = simple_strtoul(argv[1], NULL, 0); + src = simple_strtoul(argv[2], NULL, 0); + count = simple_strtoul(argv[3], NULL, 0); + + printf("copying from 0x%08x to 0x%08x (size %d)\n", src, dest, count); + + end = src + count; + + __asm__ __volatile__( + "copy_loop:\n" + "ldmia %1!, {r3-r10}\n" + "stmia %0!, {r3-r10}\n" + "cmp %1, %2\n" + "ble copy_loop\n" + : + : "r" (dest), "r" (src), "r" (end) + : "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10"); + + return 0; +} + +U_BOOT_CMD_START(mcpy_test) + .maxargs = CONFIG_MAXARGS, + .cmd = do_mcpy_test, + .usage = "Adjust CLKO setting", +U_BOOT_CMD_END + diff --git a/arch/arm/mach-imx/speed-imx27.c b/arch/arm/mach-imx/speed-imx27.c index 5a2cdf1..f5f5ff3 100644 --- a/arch/arm/mach-imx/speed-imx27.c +++ b/arch/arm/mach-imx/speed-imx27.c @@ -172,3 +172,40 @@ late_initcall(imx_dump_clocks); +/* + * Set the divider of the CLKO pin. Returns + * the new divider (which may be smaller + * than the desired one) + */ +int imx_clko_set_div(int div) +{ + ulong pcdr; + div--; + div &= 0x7; + + pcdr = PCDR0 & ~(7 << 22); + pcdr |= div << 22; + PCDR0 = pcdr; + + return div + 1; +} + +/* + * Set the clock source for the CLKO pin + */ +void imx_clko_set_src(int src) +{ + unsigned long ccsr; + + if (src < 0) { + PCDR0 &= ~(1 << 25); + return; + } + + ccsr = CCSR & ~0x1f; + ccsr |= src & 0x1f; + CCSR = ccsr; + + PCDR0 |= (1 << 25); +} + diff --git a/arch/arm/mach-imx/speed-imx35.c b/arch/arm/mach-imx/speed-imx35.c index f9a28e6..a16c0fa 100644 --- a/arch/arm/mach-imx/speed-imx35.c +++ b/arch/arm/mach-imx/speed-imx35.c @@ -56,34 +56,17 @@ { .arm = 0, .ahb = 0, .sel = 0}, }; -static struct arm_ahb_div clk_automotive[] = { - { .arm = 1, .ahb = 3, .sel = 0}, - { .arm = 1, .ahb = 2, .sel = 1}, - { .arm = 2, .ahb = 1, .sel = 1}, - { .arm = 0, .ahb = 0, .sel = 0}, - { .arm = 1, .ahb = 6, .sel = 0}, - { .arm = 1, .ahb = 4, .sel = 1}, - { .arm = 2, .ahb = 2, .sel = 1}, - { .arm = 0, .ahb = 0, .sel = 0}, -}; - unsigned long imx_get_armclk(void) { unsigned long pdr0 = readl(IMX_CCM_BASE + CCM_PDR0); struct arm_ahb_div *aad; unsigned long fref = imx_get_mpllclk(); - if (pdr0 & PDR0_AUTO_CON) { - /* consumer path is selected */ - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - if (aad->sel) - fref = fref * 2 / 3; - } else { - /* auto path is selected */ - aad = &clk_automotive[(pdr0 >> 9) & 0x7]; - if (aad->sel) - fref = fref * 3 / 4; - } + /* consumer path is selected */ + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; + if (aad->sel) + fref = fref * 2 / 3; + return fref / aad->arm; } @@ -93,12 +76,7 @@ struct arm_ahb_div *aad; unsigned long fref = imx_get_mpllclk(); - if (pdr0 & PDR0_AUTO_CON) - /* consumer path is selected */ - aad = &clk_consumer[(pdr0 >> 16) & 0xf]; - else - /* auto path is selected */ - aad = &clk_automotive[(pdr0 >> 9) & 0x7]; + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; return fref / aad->ahb; } @@ -164,3 +142,43 @@ } late_initcall(imx_dump_clocks); + +/* + * Set the divider of the CLKO pin. Returns + * the new divider (which may be smaller + * than the desired one) + */ +int imx_clko_set_div(int div) +{ + unsigned long cosr = readl(IMX_CCM_BASE + CCM_COSR); + + div -= 1; + div &= 0x3f; + + cosr &= ~(0x3f << 10); + cosr |= div << 10; + + return div + 1; +} + +/* + * Set the clock source for the CLKO pin + */ +void imx_clko_set_src(int src) +{ + unsigned long cosr = readl(IMX_CCM_BASE + CCM_COSR); + + if (src < 0) { + cosr &= ~(1 << 5); + writel(cosr, IMX_CCM_BASE + CCM_COSR); + return; + } + + cosr |= 1 << 5; + cosr &= ~0x1f; + cosr &= ~(1 << 6); + cosr |= src & 0x1f; + + writel(cosr, IMX_CCM_BASE + CCM_COSR); +} + diff --git a/include/asm-arm/arch-imx/clock.h b/include/asm-arm/arch-imx/clock.h index 7108520..c012e94 100644 --- a/include/asm-arm/arch-imx/clock.h +++ b/include/asm-arm/arch-imx/clock.h @@ -27,4 +27,7 @@ ulong imx_get_gptclk(void); ulong imx_get_uartclk(void); +int imx_clko_set_div(int div); +void imx_clko_set_src(int src); + #endif /* __ASM_ARCH_CLOCK_H */