/* * Based on Linux driver: * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. * Copyright (C) 2006 FON Technology, SL. * Copyright (C) 2006 Imre Kaloz * Copyright (C) 2006-2009 Felix Fietkau * Ported to Barebox: * Copyright (C) 2013 Oleksij Rempel * * 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 #include #include #include #include #include struct ar231x_board_data ar231x_board; /* * This table is indexed by bits 5..4 of the CLOCKCTL1 register * to determine the predevisor value. */ static int CLOCKCTL1_PREDIVIDE_TABLE[4] = { 1, 2, 4, 5 }; static unsigned int ar2312_cpu_frequency(void) { unsigned int predivide_mask, predivide_shift; unsigned int multiplier_mask, multiplier_shift; unsigned int clock_ctl1, pre_divide_select, pre_divisor, multiplier; unsigned int doubler_mask; u32 devid; devid = __raw_readl((char *)KSEG1ADDR(AR2312_REV)); devid &= AR2312_REV_MAJ; devid >>= AR2312_REV_MAJ_S; if (devid == AR2312_REV_MAJ_AR2313) { predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; } else { /* AR5312 and AR2312 */ predivide_mask = AR2312_CLOCKCTL1_PREDIVIDE_MASK; predivide_shift = AR2312_CLOCKCTL1_PREDIVIDE_SHIFT; multiplier_mask = AR2312_CLOCKCTL1_MULTIPLIER_MASK; multiplier_shift = AR2312_CLOCKCTL1_MULTIPLIER_SHIFT; doubler_mask = AR2312_CLOCKCTL1_DOUBLER_MASK; } /* * Clocking is derived from a fixed 40MHz input clock. * * cpuFreq = InputClock * MULT (where MULT is PLL multiplier) * sysFreq = cpuFreq / 4 (used for APB clock, serial, * flash, Timer, Watchdog Timer) * * cntFreq = cpuFreq / 2 (use for CPU count/compare) * * So, for example, with a PLL multiplier of 5, we have * * cpuFreq = 200MHz * sysFreq = 50MHz * cntFreq = 100MHz * * We compute the CPU frequency, based on PLL settings. */ clock_ctl1 = __raw_readl((char *)KSEG1ADDR(AR2312_CLOCKCTL1)); pre_divide_select = (clock_ctl1 & predivide_mask) >> predivide_shift; pre_divisor = CLOCKCTL1_PREDIVIDE_TABLE[pre_divide_select]; multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift; if (clock_ctl1 & doubler_mask) multiplier = multiplier << 1; return (40000000 / pre_divisor) * multiplier; } static unsigned int ar2312_sys_frequency(void) { return ar2312_cpu_frequency() / 4; } /* * shutdown watchdog */ static int watchdog_init(void) { pr_debug("Disable watchdog.\n"); __raw_writeb(AR2312_WD_CTRL_IGNORE_EXPIRATION, (char *)KSEG1ADDR(AR2312_WD_CTRL)); return 0; } static void flash_init(void) { u32 ctl, old_ctl; /* Configure flash bank 0. * Assume 8M maximum window size on this SoC. * Flash will be aliased if it's smaller */ old_ctl = __raw_readl((char *)KSEG1ADDR(AR2312_FLASHCTL0)); ctl = FLASHCTL_E | FLASHCTL_AC_8M | FLASHCTL_RBLE | (0x01 << FLASHCTL_IDCY_S) | (0x07 << FLASHCTL_WST1_S) | (0x07 << FLASHCTL_WST2_S) | (old_ctl & FLASHCTL_MW); __raw_writel(ctl, (char *)KSEG1ADDR(AR2312_FLASHCTL0)); /* Disable other flash banks */ old_ctl = __raw_readl((char *)KSEG1ADDR(AR2312_FLASHCTL1)); __raw_writel(old_ctl & ~(FLASHCTL_E | FLASHCTL_AC), (char *)KSEG1ADDR(AR2312_FLASHCTL1)); old_ctl = __raw_readl((char *)KSEG1ADDR(AR2312_FLASHCTL2)); __raw_writel(old_ctl & ~(FLASHCTL_E | FLASHCTL_AC), (char *)KSEG1ADDR(AR2312_FLASHCTL2)); /* We need to find atheros config. MAC address is there. */ ar231x_find_config((char *)KSEG1ADDR(AR2312_FLASH + AR2312_MAX_FLASH_SIZE)); } static int ether_init(void) { static struct resource res[2]; struct ar231x_eth_platform_data *eth = &ar231x_board.eth_pdata; /* Base ETH registers */ res[0].start = KSEG1ADDR(AR2312_ENET1); res[0].end = res[0].start + 0x100000 - 1; res[0].flags = IORESOURCE_MEM; /* Base PHY registers */ res[1].start = KSEG1ADDR(AR2312_ENET0); res[1].end = res[1].start + 0x100000 - 1; res[1].flags = IORESOURCE_MEM; /* MAC address located in atheros config on flash. */ eth->mac = ar231x_board.config->enet0_mac; eth->reset_mac = AR2312_RESET_ENET0 | AR2312_RESET_ENET1; eth->reset_phy = AR2312_RESET_EPHY0 | AR2312_RESET_EPHY1; eth->reset_bit = ar231x_reset_bit; /* FIXME: base_reset should be replaced with reset driver */ eth->base_reset = KSEG1ADDR(AR2312_RESET); add_generic_device_res("ar231x_eth", DEVICE_ID_DYNAMIC, res, 2, eth); return 0; } static int platform_init(void) { add_generic_device("ar231x_reset", DEVICE_ID_SINGLE, NULL, KSEG1ADDR(AR2312_RESET), 0x4, IORESOURCE_MEM, NULL); watchdog_init(); flash_init(); ether_init(); return 0; } late_initcall(platform_init); static struct NS16550_plat serial_plat = { .shift = AR2312_UART_SHIFT, }; static int ar2312_console_init(void) { u32 reset; /* reset UART0 */ reset = __raw_readl((char *)KSEG1ADDR(AR2312_RESET)); reset = ((reset & ~AR2312_RESET_APB) | AR2312_RESET_UART0); __raw_writel(reset, (char *)KSEG1ADDR(AR2312_RESET)); reset &= ~AR2312_RESET_UART0; __raw_writel(reset, (char *)KSEG1ADDR(AR2312_RESET)); /* Register the serial port */ serial_plat.clock = ar2312_sys_frequency(); add_ns16550_device(DEVICE_ID_DYNAMIC, KSEG1ADDR(AR2312_UART0), 8 << AR2312_UART_SHIFT, IORESOURCE_MEM | IORESOURCE_MEM_8BIT, &serial_plat); return 0; } console_initcall(ar2312_console_init);