18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. 78c2ecf20Sopenharmony_ci * Copyright (C) 2006 FON Technology, SL. 88c2ecf20Sopenharmony_ci * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> 98c2ecf20Sopenharmony_ci * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> 108c2ecf20Sopenharmony_ci * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com> 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * Platform devices for Atheros AR5312 SoCs 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/bitops.h> 208c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/memblock.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 258c2ecf20Sopenharmony_ci#include <linux/reboot.h> 268c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 278c2ecf20Sopenharmony_ci#include <asm/reboot.h> 288c2ecf20Sopenharmony_ci#include <asm/time.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <ath25_platform.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include "devices.h" 338c2ecf20Sopenharmony_ci#include "ar5312.h" 348c2ecf20Sopenharmony_ci#include "ar5312_regs.h" 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void __iomem *ar5312_rst_base; 378c2ecf20Sopenharmony_cistatic struct irq_domain *ar5312_misc_irq_domain; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic inline u32 ar5312_rst_reg_read(u32 reg) 408c2ecf20Sopenharmony_ci{ 418c2ecf20Sopenharmony_ci return __raw_readl(ar5312_rst_base + reg); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic inline void ar5312_rst_reg_write(u32 reg, u32 val) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci __raw_writel(val, ar5312_rst_base + reg); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci u32 ret = ar5312_rst_reg_read(reg); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ret &= ~mask; 548c2ecf20Sopenharmony_ci ret |= val; 558c2ecf20Sopenharmony_ci ar5312_rst_reg_write(reg, ret); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci u32 proc1 = ar5312_rst_reg_read(AR5312_PROC1); 618c2ecf20Sopenharmony_ci u32 proc_addr = ar5312_rst_reg_read(AR5312_PROCADDR); /* clears error */ 628c2ecf20Sopenharmony_ci u32 dma1 = ar5312_rst_reg_read(AR5312_DMA1); 638c2ecf20Sopenharmony_ci u32 dma_addr = ar5312_rst_reg_read(AR5312_DMAADDR); /* clears error */ 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", 668c2ecf20Sopenharmony_ci proc_addr, proc1, dma_addr, dma1); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci machine_restart("AHB error"); /* Catastrophic failure */ 698c2ecf20Sopenharmony_ci return IRQ_HANDLED; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void ar5312_misc_irq_handler(struct irq_desc *desc) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 pending = ar5312_rst_reg_read(AR5312_ISR) & 758c2ecf20Sopenharmony_ci ar5312_rst_reg_read(AR5312_IMR); 768c2ecf20Sopenharmony_ci unsigned nr, misc_irq = 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (pending) { 798c2ecf20Sopenharmony_ci struct irq_domain *domain = irq_desc_get_handler_data(desc); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci nr = __ffs(pending); 828c2ecf20Sopenharmony_ci misc_irq = irq_find_mapping(domain, nr); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (misc_irq) { 868c2ecf20Sopenharmony_ci generic_handle_irq(misc_irq); 878c2ecf20Sopenharmony_ci if (nr == AR5312_MISC_IRQ_TIMER) 888c2ecf20Sopenharmony_ci ar5312_rst_reg_read(AR5312_TIMER); 898c2ecf20Sopenharmony_ci } else { 908c2ecf20Sopenharmony_ci spurious_interrupt(); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/* Enable the specified AR5312_MISC_IRQ interrupt */ 958c2ecf20Sopenharmony_cistatic void ar5312_misc_irq_unmask(struct irq_data *d) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci ar5312_rst_reg_mask(AR5312_IMR, 0, BIT(d->hwirq)); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Disable the specified AR5312_MISC_IRQ interrupt */ 1018c2ecf20Sopenharmony_cistatic void ar5312_misc_irq_mask(struct irq_data *d) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci ar5312_rst_reg_mask(AR5312_IMR, BIT(d->hwirq), 0); 1048c2ecf20Sopenharmony_ci ar5312_rst_reg_read(AR5312_IMR); /* flush write buffer */ 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic struct irq_chip ar5312_misc_irq_chip = { 1088c2ecf20Sopenharmony_ci .name = "ar5312-misc", 1098c2ecf20Sopenharmony_ci .irq_unmask = ar5312_misc_irq_unmask, 1108c2ecf20Sopenharmony_ci .irq_mask = ar5312_misc_irq_mask, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int ar5312_misc_irq_map(struct irq_domain *d, unsigned irq, 1148c2ecf20Sopenharmony_ci irq_hw_number_t hw) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, handle_level_irq); 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic struct irq_domain_ops ar5312_misc_irq_domain_ops = { 1218c2ecf20Sopenharmony_ci .map = ar5312_misc_irq_map, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void ar5312_irq_dispatch(void) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci u32 pending = read_c0_status() & read_c0_cause(); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (pending & CAUSEF_IP2) 1298c2ecf20Sopenharmony_ci do_IRQ(AR5312_IRQ_WLAN0); 1308c2ecf20Sopenharmony_ci else if (pending & CAUSEF_IP5) 1318c2ecf20Sopenharmony_ci do_IRQ(AR5312_IRQ_WLAN1); 1328c2ecf20Sopenharmony_ci else if (pending & CAUSEF_IP6) 1338c2ecf20Sopenharmony_ci do_IRQ(AR5312_IRQ_MISC); 1348c2ecf20Sopenharmony_ci else if (pending & CAUSEF_IP7) 1358c2ecf20Sopenharmony_ci do_IRQ(ATH25_IRQ_CPU_CLOCK); 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci spurious_interrupt(); 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_civoid __init ar5312_arch_init_irq(void) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct irq_domain *domain; 1438c2ecf20Sopenharmony_ci unsigned irq; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci ath25_irq_dispatch = ar5312_irq_dispatch; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci domain = irq_domain_add_linear(NULL, AR5312_MISC_IRQ_COUNT, 1488c2ecf20Sopenharmony_ci &ar5312_misc_irq_domain_ops, NULL); 1498c2ecf20Sopenharmony_ci if (!domain) 1508c2ecf20Sopenharmony_ci panic("Failed to add IRQ domain"); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC); 1538c2ecf20Sopenharmony_ci if (request_irq(irq, ar5312_ahb_err_handler, 0, "ar5312-ahb-error", 1548c2ecf20Sopenharmony_ci NULL)) 1558c2ecf20Sopenharmony_ci pr_err("Failed to register ar5312-ahb-error interrupt\n"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(AR5312_IRQ_MISC, 1588c2ecf20Sopenharmony_ci ar5312_misc_irq_handler, domain); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ar5312_misc_irq_domain = domain; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic struct physmap_flash_data ar5312_flash_data = { 1648c2ecf20Sopenharmony_ci .width = 2, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic struct resource ar5312_flash_resource = { 1688c2ecf20Sopenharmony_ci .start = AR5312_FLASH_BASE, 1698c2ecf20Sopenharmony_ci .end = AR5312_FLASH_BASE + AR5312_FLASH_SIZE - 1, 1708c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic struct platform_device ar5312_physmap_flash = { 1748c2ecf20Sopenharmony_ci .name = "physmap-flash", 1758c2ecf20Sopenharmony_ci .id = 0, 1768c2ecf20Sopenharmony_ci .dev.platform_data = &ar5312_flash_data, 1778c2ecf20Sopenharmony_ci .resource = &ar5312_flash_resource, 1788c2ecf20Sopenharmony_ci .num_resources = 1, 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void __init ar5312_flash_init(void) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci void __iomem *flashctl_base; 1848c2ecf20Sopenharmony_ci u32 ctl; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci flashctl_base = ioremap(AR5312_FLASHCTL_BASE, 1878c2ecf20Sopenharmony_ci AR5312_FLASHCTL_SIZE); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL0); 1908c2ecf20Sopenharmony_ci ctl &= AR5312_FLASHCTL_MW; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* fixup flash width */ 1938c2ecf20Sopenharmony_ci switch (ctl) { 1948c2ecf20Sopenharmony_ci case AR5312_FLASHCTL_MW16: 1958c2ecf20Sopenharmony_ci ar5312_flash_data.width = 2; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci case AR5312_FLASHCTL_MW8: 1988c2ecf20Sopenharmony_ci default: 1998c2ecf20Sopenharmony_ci ar5312_flash_data.width = 1; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* 2048c2ecf20Sopenharmony_ci * Configure flash bank 0. 2058c2ecf20Sopenharmony_ci * Assume 8M window size. Flash will be aliased if it's smaller 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE; 2088c2ecf20Sopenharmony_ci ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S; 2098c2ecf20Sopenharmony_ci ctl |= 0x07 << AR5312_FLASHCTL_WST1_S; 2108c2ecf20Sopenharmony_ci ctl |= 0x07 << AR5312_FLASHCTL_WST2_S; 2118c2ecf20Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL0); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Disable other flash banks */ 2148c2ecf20Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL1); 2158c2ecf20Sopenharmony_ci ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); 2168c2ecf20Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL1); 2178c2ecf20Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL2); 2188c2ecf20Sopenharmony_ci ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); 2198c2ecf20Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci iounmap(flashctl_base); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_civoid __init ar5312_init_devices(void) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct ath25_boarddata *config; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci ar5312_flash_init(); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Locate board/radio config data */ 2318c2ecf20Sopenharmony_ci ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE); 2328c2ecf20Sopenharmony_ci config = ath25_board.config; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci /* AR2313 has CPU minor rev. 10 */ 2358c2ecf20Sopenharmony_ci if ((current_cpu_data.processor_id & 0xff) == 0x0a) 2368c2ecf20Sopenharmony_ci ath25_soc = ATH25_SOC_AR2313; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* AR2312 shares the same Silicon ID as AR5312 */ 2398c2ecf20Sopenharmony_ci else if (config->flags & BD_ISCASPER) 2408c2ecf20Sopenharmony_ci ath25_soc = ATH25_SOC_AR2312; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Everything else is probably AR5312 or compatible */ 2438c2ecf20Sopenharmony_ci else 2448c2ecf20Sopenharmony_ci ath25_soc = ATH25_SOC_AR5312; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci platform_device_register(&ar5312_physmap_flash); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch (ath25_soc) { 2498c2ecf20Sopenharmony_ci case ATH25_SOC_AR5312: 2508c2ecf20Sopenharmony_ci if (!ath25_board.radio) 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (!(config->flags & BD_WLAN0)) 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0); 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci case ATH25_SOC_AR2312: 2598c2ecf20Sopenharmony_ci case ATH25_SOC_AR2313: 2608c2ecf20Sopenharmony_ci if (!ath25_board.radio) 2618c2ecf20Sopenharmony_ci return; 2628c2ecf20Sopenharmony_ci break; 2638c2ecf20Sopenharmony_ci default: 2648c2ecf20Sopenharmony_ci break; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (config->flags & BD_WLAN1) 2688c2ecf20Sopenharmony_ci ath25_add_wmac(1, AR5312_WLAN1_BASE, AR5312_IRQ_WLAN1); 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void ar5312_restart(char *command) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci /* reset the system */ 2748c2ecf20Sopenharmony_ci local_irq_disable(); 2758c2ecf20Sopenharmony_ci while (1) 2768c2ecf20Sopenharmony_ci ar5312_rst_reg_write(AR5312_RESET, AR5312_RESET_SYSTEM); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* 2808c2ecf20Sopenharmony_ci * This table is indexed by bits 5..4 of the CLOCKCTL1 register 2818c2ecf20Sopenharmony_ci * to determine the predevisor value. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic unsigned clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 }; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic unsigned __init ar5312_cpu_frequency(void) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci u32 scratch, devid, clock_ctl1; 2888c2ecf20Sopenharmony_ci u32 predivide_mask, multiplier_mask, doubler_mask; 2898c2ecf20Sopenharmony_ci unsigned predivide_shift, multiplier_shift; 2908c2ecf20Sopenharmony_ci unsigned predivide_select, predivisor, multiplier; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* Trust the bootrom's idea of cpu frequency. */ 2938c2ecf20Sopenharmony_ci scratch = ar5312_rst_reg_read(AR5312_SCRATCH); 2948c2ecf20Sopenharmony_ci if (scratch) 2958c2ecf20Sopenharmony_ci return scratch; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci devid = ar5312_rst_reg_read(AR5312_REV); 2988c2ecf20Sopenharmony_ci devid = (devid & AR5312_REV_MAJ) >> AR5312_REV_MAJ_S; 2998c2ecf20Sopenharmony_ci if (devid == AR5312_REV_MAJ_AR2313) { 3008c2ecf20Sopenharmony_ci predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; 3018c2ecf20Sopenharmony_ci predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; 3028c2ecf20Sopenharmony_ci multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; 3038c2ecf20Sopenharmony_ci multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; 3048c2ecf20Sopenharmony_ci doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; 3058c2ecf20Sopenharmony_ci } else { /* AR5312 and AR2312 */ 3068c2ecf20Sopenharmony_ci predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK; 3078c2ecf20Sopenharmony_ci predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT; 3088c2ecf20Sopenharmony_ci multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK; 3098c2ecf20Sopenharmony_ci multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT; 3108c2ecf20Sopenharmony_ci doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * Clocking is derived from a fixed 40MHz input clock. 3158c2ecf20Sopenharmony_ci * 3168c2ecf20Sopenharmony_ci * cpu_freq = input_clock * MULT (where MULT is PLL multiplier) 3178c2ecf20Sopenharmony_ci * sys_freq = cpu_freq / 4 (used for APB clock, serial, 3188c2ecf20Sopenharmony_ci * flash, Timer, Watchdog Timer) 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * cnt_freq = cpu_freq / 2 (use for CPU count/compare) 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * So, for example, with a PLL multiplier of 5, we have 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * cpu_freq = 200MHz 3258c2ecf20Sopenharmony_ci * sys_freq = 50MHz 3268c2ecf20Sopenharmony_ci * cnt_freq = 100MHz 3278c2ecf20Sopenharmony_ci * 3288c2ecf20Sopenharmony_ci * We compute the CPU frequency, based on PLL settings. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci clock_ctl1 = ar5312_rst_reg_read(AR5312_CLOCKCTL1); 3328c2ecf20Sopenharmony_ci predivide_select = (clock_ctl1 & predivide_mask) >> predivide_shift; 3338c2ecf20Sopenharmony_ci predivisor = clockctl1_predivide_table[predivide_select]; 3348c2ecf20Sopenharmony_ci multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (clock_ctl1 & doubler_mask) 3378c2ecf20Sopenharmony_ci multiplier <<= 1; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return (40000000 / predivisor) * multiplier; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic inline unsigned ar5312_sys_frequency(void) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci return ar5312_cpu_frequency() / 4; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_civoid __init ar5312_plat_time_init(void) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci mips_hpt_frequency = ar5312_cpu_frequency() / 2; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_civoid __init ar5312_plat_mem_setup(void) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci void __iomem *sdram_base; 3558c2ecf20Sopenharmony_ci u32 memsize, memcfg, bank0_ac, bank1_ac; 3568c2ecf20Sopenharmony_ci u32 devid; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* Detect memory size */ 3598c2ecf20Sopenharmony_ci sdram_base = ioremap(AR5312_SDRAMCTL_BASE, 3608c2ecf20Sopenharmony_ci AR5312_SDRAMCTL_SIZE); 3618c2ecf20Sopenharmony_ci memcfg = __raw_readl(sdram_base + AR5312_MEM_CFG1); 3628c2ecf20Sopenharmony_ci bank0_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC0); 3638c2ecf20Sopenharmony_ci bank1_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC1); 3648c2ecf20Sopenharmony_ci memsize = (bank0_ac ? (1 << (bank0_ac + 1)) : 0) + 3658c2ecf20Sopenharmony_ci (bank1_ac ? (1 << (bank1_ac + 1)) : 0); 3668c2ecf20Sopenharmony_ci memsize <<= 20; 3678c2ecf20Sopenharmony_ci memblock_add(0, memsize); 3688c2ecf20Sopenharmony_ci iounmap(sdram_base); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ar5312_rst_base = ioremap(AR5312_RST_BASE, AR5312_RST_SIZE); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci devid = ar5312_rst_reg_read(AR5312_REV); 3738c2ecf20Sopenharmony_ci devid >>= AR5312_REV_WMAC_MIN_S; 3748c2ecf20Sopenharmony_ci devid &= AR5312_REV_CHIP; 3758c2ecf20Sopenharmony_ci ath25_board.devid = (u16)devid; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* Clear any lingering AHB errors */ 3788c2ecf20Sopenharmony_ci ar5312_rst_reg_read(AR5312_PROCADDR); 3798c2ecf20Sopenharmony_ci ar5312_rst_reg_read(AR5312_DMAADDR); 3808c2ecf20Sopenharmony_ci ar5312_rst_reg_write(AR5312_WDT_CTRL, AR5312_WDT_CTRL_IGNORE); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci _machine_restart = ar5312_restart; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_civoid __init ar5312_arch_init(void) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci unsigned irq = irq_create_mapping(ar5312_misc_irq_domain, 3888c2ecf20Sopenharmony_ci AR5312_MISC_IRQ_UART0); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ath25_serial_setup(AR5312_UART0_BASE, irq, ar5312_sys_frequency()); 3918c2ecf20Sopenharmony_ci} 392