162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2003 Atheros Communications, Inc., All Rights Reserved. 762306a36Sopenharmony_ci * Copyright (C) 2006 FON Technology, SL. 862306a36Sopenharmony_ci * Copyright (C) 2006 Imre Kaloz <kaloz@openwrt.org> 962306a36Sopenharmony_ci * Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org> 1062306a36Sopenharmony_ci * Copyright (C) 2012 Alexandros C. Couloumbis <alex@ozo.com> 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * Platform devices for Atheros AR5312 SoCs 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/kernel.h> 1962306a36Sopenharmony_ci#include <linux/bitops.h> 2062306a36Sopenharmony_ci#include <linux/irqdomain.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/memblock.h> 2362306a36Sopenharmony_ci#include <linux/platform_device.h> 2462306a36Sopenharmony_ci#include <linux/mtd/physmap.h> 2562306a36Sopenharmony_ci#include <linux/reboot.h> 2662306a36Sopenharmony_ci#include <asm/bootinfo.h> 2762306a36Sopenharmony_ci#include <asm/reboot.h> 2862306a36Sopenharmony_ci#include <asm/time.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <ath25_platform.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "devices.h" 3362306a36Sopenharmony_ci#include "ar5312.h" 3462306a36Sopenharmony_ci#include "ar5312_regs.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void __iomem *ar5312_rst_base; 3762306a36Sopenharmony_cistatic struct irq_domain *ar5312_misc_irq_domain; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic inline u32 ar5312_rst_reg_read(u32 reg) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci return __raw_readl(ar5312_rst_base + reg); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic inline void ar5312_rst_reg_write(u32 reg, u32 val) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci __raw_writel(val, ar5312_rst_base + reg); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic inline void ar5312_rst_reg_mask(u32 reg, u32 mask, u32 val) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci u32 ret = ar5312_rst_reg_read(reg); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci ret &= ~mask; 5462306a36Sopenharmony_ci ret |= val; 5562306a36Sopenharmony_ci ar5312_rst_reg_write(reg, ret); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic irqreturn_t ar5312_ahb_err_handler(int cpl, void *dev_id) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci u32 proc1 = ar5312_rst_reg_read(AR5312_PROC1); 6162306a36Sopenharmony_ci u32 proc_addr = ar5312_rst_reg_read(AR5312_PROCADDR); /* clears error */ 6262306a36Sopenharmony_ci u32 dma1 = ar5312_rst_reg_read(AR5312_DMA1); 6362306a36Sopenharmony_ci u32 dma_addr = ar5312_rst_reg_read(AR5312_DMAADDR); /* clears error */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci pr_emerg("AHB interrupt: PROCADDR=0x%8.8x PROC1=0x%8.8x DMAADDR=0x%8.8x DMA1=0x%8.8x\n", 6662306a36Sopenharmony_ci proc_addr, proc1, dma_addr, dma1); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci machine_restart("AHB error"); /* Catastrophic failure */ 6962306a36Sopenharmony_ci return IRQ_HANDLED; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void ar5312_misc_irq_handler(struct irq_desc *desc) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci u32 pending = ar5312_rst_reg_read(AR5312_ISR) & 7562306a36Sopenharmony_ci ar5312_rst_reg_read(AR5312_IMR); 7662306a36Sopenharmony_ci unsigned nr; 7762306a36Sopenharmony_ci int ret = 0; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (pending) { 8062306a36Sopenharmony_ci struct irq_domain *domain = irq_desc_get_handler_data(desc); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci nr = __ffs(pending); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci ret = generic_handle_domain_irq(domain, nr); 8562306a36Sopenharmony_ci if (nr == AR5312_MISC_IRQ_TIMER) 8662306a36Sopenharmony_ci ar5312_rst_reg_read(AR5312_TIMER); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (!pending || ret) 9062306a36Sopenharmony_ci spurious_interrupt(); 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Enable the specified AR5312_MISC_IRQ interrupt */ 9462306a36Sopenharmony_cistatic void ar5312_misc_irq_unmask(struct irq_data *d) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci ar5312_rst_reg_mask(AR5312_IMR, 0, BIT(d->hwirq)); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* Disable the specified AR5312_MISC_IRQ interrupt */ 10062306a36Sopenharmony_cistatic void ar5312_misc_irq_mask(struct irq_data *d) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci ar5312_rst_reg_mask(AR5312_IMR, BIT(d->hwirq), 0); 10362306a36Sopenharmony_ci ar5312_rst_reg_read(AR5312_IMR); /* flush write buffer */ 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic struct irq_chip ar5312_misc_irq_chip = { 10762306a36Sopenharmony_ci .name = "ar5312-misc", 10862306a36Sopenharmony_ci .irq_unmask = ar5312_misc_irq_unmask, 10962306a36Sopenharmony_ci .irq_mask = ar5312_misc_irq_mask, 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic int ar5312_misc_irq_map(struct irq_domain *d, unsigned irq, 11362306a36Sopenharmony_ci irq_hw_number_t hw) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci irq_set_chip_and_handler(irq, &ar5312_misc_irq_chip, handle_level_irq); 11662306a36Sopenharmony_ci return 0; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic const struct irq_domain_ops ar5312_misc_irq_domain_ops = { 12062306a36Sopenharmony_ci .map = ar5312_misc_irq_map, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic void ar5312_irq_dispatch(void) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci u32 pending = read_c0_status() & read_c0_cause(); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci if (pending & CAUSEF_IP2) 12862306a36Sopenharmony_ci do_IRQ(AR5312_IRQ_WLAN0); 12962306a36Sopenharmony_ci else if (pending & CAUSEF_IP5) 13062306a36Sopenharmony_ci do_IRQ(AR5312_IRQ_WLAN1); 13162306a36Sopenharmony_ci else if (pending & CAUSEF_IP6) 13262306a36Sopenharmony_ci do_IRQ(AR5312_IRQ_MISC); 13362306a36Sopenharmony_ci else if (pending & CAUSEF_IP7) 13462306a36Sopenharmony_ci do_IRQ(ATH25_IRQ_CPU_CLOCK); 13562306a36Sopenharmony_ci else 13662306a36Sopenharmony_ci spurious_interrupt(); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid __init ar5312_arch_init_irq(void) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct irq_domain *domain; 14262306a36Sopenharmony_ci unsigned irq; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci ath25_irq_dispatch = ar5312_irq_dispatch; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci domain = irq_domain_add_linear(NULL, AR5312_MISC_IRQ_COUNT, 14762306a36Sopenharmony_ci &ar5312_misc_irq_domain_ops, NULL); 14862306a36Sopenharmony_ci if (!domain) 14962306a36Sopenharmony_ci panic("Failed to add IRQ domain"); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci irq = irq_create_mapping(domain, AR5312_MISC_IRQ_AHB_PROC); 15262306a36Sopenharmony_ci if (request_irq(irq, ar5312_ahb_err_handler, 0, "ar5312-ahb-error", 15362306a36Sopenharmony_ci NULL)) 15462306a36Sopenharmony_ci pr_err("Failed to register ar5312-ahb-error interrupt\n"); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci irq_set_chained_handler_and_data(AR5312_IRQ_MISC, 15762306a36Sopenharmony_ci ar5312_misc_irq_handler, domain); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci ar5312_misc_irq_domain = domain; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic struct physmap_flash_data ar5312_flash_data = { 16362306a36Sopenharmony_ci .width = 2, 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic struct resource ar5312_flash_resource = { 16762306a36Sopenharmony_ci .start = AR5312_FLASH_BASE, 16862306a36Sopenharmony_ci .end = AR5312_FLASH_BASE + AR5312_FLASH_SIZE - 1, 16962306a36Sopenharmony_ci .flags = IORESOURCE_MEM, 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic struct platform_device ar5312_physmap_flash = { 17362306a36Sopenharmony_ci .name = "physmap-flash", 17462306a36Sopenharmony_ci .id = 0, 17562306a36Sopenharmony_ci .dev.platform_data = &ar5312_flash_data, 17662306a36Sopenharmony_ci .resource = &ar5312_flash_resource, 17762306a36Sopenharmony_ci .num_resources = 1, 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void __init ar5312_flash_init(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci void __iomem *flashctl_base; 18362306a36Sopenharmony_ci u32 ctl; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci flashctl_base = ioremap(AR5312_FLASHCTL_BASE, 18662306a36Sopenharmony_ci AR5312_FLASHCTL_SIZE); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL0); 18962306a36Sopenharmony_ci ctl &= AR5312_FLASHCTL_MW; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci /* fixup flash width */ 19262306a36Sopenharmony_ci switch (ctl) { 19362306a36Sopenharmony_ci case AR5312_FLASHCTL_MW16: 19462306a36Sopenharmony_ci ar5312_flash_data.width = 2; 19562306a36Sopenharmony_ci break; 19662306a36Sopenharmony_ci case AR5312_FLASHCTL_MW8: 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci ar5312_flash_data.width = 1; 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * Configure flash bank 0. 20462306a36Sopenharmony_ci * Assume 8M window size. Flash will be aliased if it's smaller 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci ctl |= AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC_8M | AR5312_FLASHCTL_RBLE; 20762306a36Sopenharmony_ci ctl |= 0x01 << AR5312_FLASHCTL_IDCY_S; 20862306a36Sopenharmony_ci ctl |= 0x07 << AR5312_FLASHCTL_WST1_S; 20962306a36Sopenharmony_ci ctl |= 0x07 << AR5312_FLASHCTL_WST2_S; 21062306a36Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL0); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* Disable other flash banks */ 21362306a36Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL1); 21462306a36Sopenharmony_ci ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); 21562306a36Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL1); 21662306a36Sopenharmony_ci ctl = __raw_readl(flashctl_base + AR5312_FLASHCTL2); 21762306a36Sopenharmony_ci ctl &= ~(AR5312_FLASHCTL_E | AR5312_FLASHCTL_AC); 21862306a36Sopenharmony_ci __raw_writel(ctl, flashctl_base + AR5312_FLASHCTL2); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci iounmap(flashctl_base); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_civoid __init ar5312_init_devices(void) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct ath25_boarddata *config; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci ar5312_flash_init(); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Locate board/radio config data */ 23062306a36Sopenharmony_ci ath25_find_config(AR5312_FLASH_BASE, AR5312_FLASH_SIZE); 23162306a36Sopenharmony_ci config = ath25_board.config; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* AR2313 has CPU minor rev. 10 */ 23462306a36Sopenharmony_ci if ((current_cpu_data.processor_id & 0xff) == 0x0a) 23562306a36Sopenharmony_ci ath25_soc = ATH25_SOC_AR2313; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* AR2312 shares the same Silicon ID as AR5312 */ 23862306a36Sopenharmony_ci else if (config->flags & BD_ISCASPER) 23962306a36Sopenharmony_ci ath25_soc = ATH25_SOC_AR2312; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* Everything else is probably AR5312 or compatible */ 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci ath25_soc = ATH25_SOC_AR5312; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci platform_device_register(&ar5312_physmap_flash); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci switch (ath25_soc) { 24862306a36Sopenharmony_ci case ATH25_SOC_AR5312: 24962306a36Sopenharmony_ci if (!ath25_board.radio) 25062306a36Sopenharmony_ci return; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (!(config->flags & BD_WLAN0)) 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ath25_add_wmac(0, AR5312_WLAN0_BASE, AR5312_IRQ_WLAN0); 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case ATH25_SOC_AR2312: 25862306a36Sopenharmony_ci case ATH25_SOC_AR2313: 25962306a36Sopenharmony_ci if (!ath25_board.radio) 26062306a36Sopenharmony_ci return; 26162306a36Sopenharmony_ci break; 26262306a36Sopenharmony_ci default: 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (config->flags & BD_WLAN1) 26762306a36Sopenharmony_ci ath25_add_wmac(1, AR5312_WLAN1_BASE, AR5312_IRQ_WLAN1); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic void ar5312_restart(char *command) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci /* reset the system */ 27362306a36Sopenharmony_ci local_irq_disable(); 27462306a36Sopenharmony_ci while (1) 27562306a36Sopenharmony_ci ar5312_rst_reg_write(AR5312_RESET, AR5312_RESET_SYSTEM); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/* 27962306a36Sopenharmony_ci * This table is indexed by bits 5..4 of the CLOCKCTL1 register 28062306a36Sopenharmony_ci * to determine the predevisor value. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_cistatic unsigned clockctl1_predivide_table[4] __initdata = { 1, 2, 4, 5 }; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic unsigned __init ar5312_cpu_frequency(void) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci u32 scratch, devid, clock_ctl1; 28762306a36Sopenharmony_ci u32 predivide_mask, multiplier_mask, doubler_mask; 28862306a36Sopenharmony_ci unsigned predivide_shift, multiplier_shift; 28962306a36Sopenharmony_ci unsigned predivide_select, predivisor, multiplier; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Trust the bootrom's idea of cpu frequency. */ 29262306a36Sopenharmony_ci scratch = ar5312_rst_reg_read(AR5312_SCRATCH); 29362306a36Sopenharmony_ci if (scratch) 29462306a36Sopenharmony_ci return scratch; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci devid = ar5312_rst_reg_read(AR5312_REV); 29762306a36Sopenharmony_ci devid = (devid & AR5312_REV_MAJ) >> AR5312_REV_MAJ_S; 29862306a36Sopenharmony_ci if (devid == AR5312_REV_MAJ_AR2313) { 29962306a36Sopenharmony_ci predivide_mask = AR2313_CLOCKCTL1_PREDIVIDE_MASK; 30062306a36Sopenharmony_ci predivide_shift = AR2313_CLOCKCTL1_PREDIVIDE_SHIFT; 30162306a36Sopenharmony_ci multiplier_mask = AR2313_CLOCKCTL1_MULTIPLIER_MASK; 30262306a36Sopenharmony_ci multiplier_shift = AR2313_CLOCKCTL1_MULTIPLIER_SHIFT; 30362306a36Sopenharmony_ci doubler_mask = AR2313_CLOCKCTL1_DOUBLER_MASK; 30462306a36Sopenharmony_ci } else { /* AR5312 and AR2312 */ 30562306a36Sopenharmony_ci predivide_mask = AR5312_CLOCKCTL1_PREDIVIDE_MASK; 30662306a36Sopenharmony_ci predivide_shift = AR5312_CLOCKCTL1_PREDIVIDE_SHIFT; 30762306a36Sopenharmony_ci multiplier_mask = AR5312_CLOCKCTL1_MULTIPLIER_MASK; 30862306a36Sopenharmony_ci multiplier_shift = AR5312_CLOCKCTL1_MULTIPLIER_SHIFT; 30962306a36Sopenharmony_ci doubler_mask = AR5312_CLOCKCTL1_DOUBLER_MASK; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * Clocking is derived from a fixed 40MHz input clock. 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * cpu_freq = input_clock * MULT (where MULT is PLL multiplier) 31662306a36Sopenharmony_ci * sys_freq = cpu_freq / 4 (used for APB clock, serial, 31762306a36Sopenharmony_ci * flash, Timer, Watchdog Timer) 31862306a36Sopenharmony_ci * 31962306a36Sopenharmony_ci * cnt_freq = cpu_freq / 2 (use for CPU count/compare) 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * So, for example, with a PLL multiplier of 5, we have 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * cpu_freq = 200MHz 32462306a36Sopenharmony_ci * sys_freq = 50MHz 32562306a36Sopenharmony_ci * cnt_freq = 100MHz 32662306a36Sopenharmony_ci * 32762306a36Sopenharmony_ci * We compute the CPU frequency, based on PLL settings. 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci clock_ctl1 = ar5312_rst_reg_read(AR5312_CLOCKCTL1); 33162306a36Sopenharmony_ci predivide_select = (clock_ctl1 & predivide_mask) >> predivide_shift; 33262306a36Sopenharmony_ci predivisor = clockctl1_predivide_table[predivide_select]; 33362306a36Sopenharmony_ci multiplier = (clock_ctl1 & multiplier_mask) >> multiplier_shift; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (clock_ctl1 & doubler_mask) 33662306a36Sopenharmony_ci multiplier <<= 1; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return (40000000 / predivisor) * multiplier; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic inline unsigned ar5312_sys_frequency(void) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci return ar5312_cpu_frequency() / 4; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_civoid __init ar5312_plat_time_init(void) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci mips_hpt_frequency = ar5312_cpu_frequency() / 2; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_civoid __init ar5312_plat_mem_setup(void) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci void __iomem *sdram_base; 35462306a36Sopenharmony_ci u32 memsize, memcfg, bank0_ac, bank1_ac; 35562306a36Sopenharmony_ci u32 devid; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Detect memory size */ 35862306a36Sopenharmony_ci sdram_base = ioremap(AR5312_SDRAMCTL_BASE, 35962306a36Sopenharmony_ci AR5312_SDRAMCTL_SIZE); 36062306a36Sopenharmony_ci memcfg = __raw_readl(sdram_base + AR5312_MEM_CFG1); 36162306a36Sopenharmony_ci bank0_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC0); 36262306a36Sopenharmony_ci bank1_ac = ATH25_REG_MS(memcfg, AR5312_MEM_CFG1_AC1); 36362306a36Sopenharmony_ci memsize = (bank0_ac ? (1 << (bank0_ac + 1)) : 0) + 36462306a36Sopenharmony_ci (bank1_ac ? (1 << (bank1_ac + 1)) : 0); 36562306a36Sopenharmony_ci memsize <<= 20; 36662306a36Sopenharmony_ci memblock_add(0, memsize); 36762306a36Sopenharmony_ci iounmap(sdram_base); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ar5312_rst_base = ioremap(AR5312_RST_BASE, AR5312_RST_SIZE); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci devid = ar5312_rst_reg_read(AR5312_REV); 37262306a36Sopenharmony_ci devid >>= AR5312_REV_WMAC_MIN_S; 37362306a36Sopenharmony_ci devid &= AR5312_REV_CHIP; 37462306a36Sopenharmony_ci ath25_board.devid = (u16)devid; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Clear any lingering AHB errors */ 37762306a36Sopenharmony_ci ar5312_rst_reg_read(AR5312_PROCADDR); 37862306a36Sopenharmony_ci ar5312_rst_reg_read(AR5312_DMAADDR); 37962306a36Sopenharmony_ci ar5312_rst_reg_write(AR5312_WDT_CTRL, AR5312_WDT_CTRL_IGNORE); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci _machine_restart = ar5312_restart; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_civoid __init ar5312_arch_init(void) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci unsigned irq = irq_create_mapping(ar5312_misc_irq_domain, 38762306a36Sopenharmony_ci AR5312_MISC_IRQ_UART0); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ath25_serial_setup(AR5312_UART0_BASE, irq, ar5312_sys_frequency()); 39062306a36Sopenharmony_ci} 391