Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * arch/arm/mach-sun5i/core.c
- *
- * (C) Copyright 2007-2012
- * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
- * Benn Huang <benn@allwinnertech.com>
- *
- * SUN5I machine core implementations
- *
- * 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
- */
- #include <linux/init.h>
- #include <linux/device.h>
- #include <linux/dma-mapping.h>
- #include <linux/platform_device.h>
- #include <linux/device.h>
- #include <linux/interrupt.h>
- #include <linux/amba/bus.h>
- #include <linux/amba/clcd.h>
- #include <linux/amba/pl061.h>
- #include <linux/amba/mmci.h>
- #include <linux/amba/pl022.h>
- #include <linux/io.h>
- #include <linux/gfp.h>
- #include <linux/clockchips.h>
- #include <linux/memblock.h>
- #include <linux/bootmem.h>
- #include <linux/export.h>
- #include <linux/clkdev.h>
- #include <linux/ipipe.h>
- #include <linux/ipipe_tickdev.h>
- #include <asm/system.h>
- #include <asm/irq.h>
- #include <asm/leds.h>
- #include <asm/hardware/arm_timer.h>
- #include <asm/hardware/icst.h>
- #include <asm/hardware/vic.h>
- #include <asm/mach-types.h>
- #include <asm/setup.h>
- #include <asm/delay.h>
- #include <asm/mach/arch.h>
- #include <asm/mach/flash.h>
- #include <asm/mach/irq.h>
- #include <asm/mach/time.h>
- #include <asm/mach/map.h>
- #include <mach/memory.h>
- #include <mach/system.h>
- #include <mach/timex.h>
- #include <plat/core.h>
- #include <plat/sys_config.h>
- /**
- * Machine Implementations
- *
- */
- static struct map_desc sw_io_desc[] __initdata = {
- { SW_VA_SRAM_BASE, __phys_to_pfn(SW_PA_SRAM_BASE), (SZ_128K + SZ_64K), MT_MEMORY_ITCM },
- { SW_VA_IO_BASE, __phys_to_pfn(SW_PA_IO_BASE), (SZ_1M + SZ_2M), MT_DEVICE },
- { SW_VA_BROM_BASE, __phys_to_pfn(SW_PA_BROM_BASE), (SZ_64K), MT_MEMORY_ITCM },
- };
- void __init sw_core_map_io(void)
- {
- iotable_init(sw_io_desc, ARRAY_SIZE(sw_io_desc));
- sunxi_pr_chip_id();
- }
- #ifdef CONFIG_FB_SUNXI_RESERVED_MEM
- unsigned long fb_start = (PLAT_PHYS_OFFSET + SZ_512M - SZ_64M - SZ_32M);
- unsigned long fb_size = SZ_32M;
- EXPORT_SYMBOL(fb_start);
- EXPORT_SYMBOL(fb_size);
- static inline void reserve_fb(void)
- {
- memblock_reserve(fb_start, fb_size);
- pr_reserve_info("LCD ", fb_start, fb_size);
- }
- #else
- static inline void reserve_fb(void) {}
- #endif
- #if 0
- unsigned long g2d_start = (PLAT_PHYS_OFFSET + SZ_512M - SZ_128M);
- unsigned long g2d_size = SZ_1M * 16;
- EXPORT_SYMBOL(g2d_start);
- EXPORT_SYMBOL(g2d_size);
- static inline void reserve_g2d(void)
- {
- int g2d_used = 0;
- char *script_base = (char *)(PAGE_OFFSET + 0x3000000);
- g2d_used = sw_cfg_get_int(script_base, "g2d_para", "g2d_used");
- if (g2d_used > 0) {
- int size = sw_cfg_get_int(script_base, "g2d_para", "g2d_size");
- if (size < 0 || size > SW_G2D_MEM_MAX)
- g2d_size = SW_G2D_MEM_MAX;
- else
- g2d_size = size;
- memblock_reserve(g2d_start, g2d_size);
- pr_reserve_info("G2D ", g2d_start, g2d_size);
- }
- }
- #else
- static inline void reserve_g2d(void) {}
- #endif
- #if defined CONFIG_VIDEO_DECODER_SUN5I || defined CONFIG_VIDEO_DECODER_SUN5I_MODULE
- unsigned long ve_start = (PLAT_PHYS_OFFSET + SZ_64M);
- unsigned long ve_size = (SZ_64M + SZ_16M);
- EXPORT_SYMBOL(ve_start);
- EXPORT_SYMBOL(ve_size);
- static inline void reserve_ve(void)
- {
- memblock_reserve(ve_start, SZ_64M);
- memblock_reserve(ve_start + SZ_64M, SZ_16M);
- pr_reserve_info("VE ", ve_start, ve_size);
- }
- #else
- static inline void reserve_ve(void) {}
- #endif
- static inline void reserve_sys(void)
- {
- memblock_reserve(SYS_CONFIG_MEMBASE, SYS_CONFIG_MEMSIZE);
- pr_reserve_info("SYS ", SYS_CONFIG_MEMBASE, SYS_CONFIG_MEMSIZE);
- }
- static void __init sw_core_reserve(void)
- {
- pr_info("Memory Reserved:\n");
- reserve_sys();
- reserve_fb();
- reserve_g2d();
- reserve_ve();
- }
- void sw_irq_ack(struct irq_data *irqd)
- {
- unsigned int irq = irqd->irq;
- if (irq < 32){
- writel(readl(SW_INT_ENABLE_REG0) & ~(1<<irq), SW_INT_ENABLE_REG0);
- writel(readl(SW_INT_MASK_REG0) | (1 << irq), SW_INT_MASK_REG0);
- writel(readl(SW_INT_IRQ_PENDING_REG0) | (1<<irq), SW_INT_IRQ_PENDING_REG0);
- } else if(irq < 64){
- irq -= 32;
- writel(readl(SW_INT_ENABLE_REG1) & ~(1<<irq), SW_INT_ENABLE_REG1);
- writel(readl(SW_INT_MASK_REG1) | (1 << irq), SW_INT_MASK_REG1);
- writel(readl(SW_INT_IRQ_PENDING_REG1) | (1<<irq), SW_INT_IRQ_PENDING_REG1);
- } else if(irq < 96){
- irq -= 64;
- writel(readl(SW_INT_ENABLE_REG2) & ~(1<<irq), SW_INT_ENABLE_REG2);
- writel(readl(SW_INT_MASK_REG2) | (1 << irq), SW_INT_MASK_REG2);
- writel(readl(SW_INT_IRQ_PENDING_REG2) | (1<<irq), SW_INT_IRQ_PENDING_REG2);
- }
- }
- /* Mask an IRQ line, which means disabling the IRQ line */
- static void sw_irq_mask(struct irq_data *irqd)
- {
- unsigned int irq = irqd->irq;
- if(irq < 32){
- writel(readl(SW_INT_ENABLE_REG0) & ~(1<<irq), SW_INT_ENABLE_REG0);
- writel(readl(SW_INT_MASK_REG0) | (1 << irq), SW_INT_MASK_REG0);
- } else if(irq < 64){
- irq -= 32;
- writel(readl(SW_INT_ENABLE_REG1) & ~(1<<irq), SW_INT_ENABLE_REG1);
- writel(readl(SW_INT_MASK_REG1) | (1 << irq), SW_INT_MASK_REG1);
- } else if(irq < 96){
- irq -= 64;
- writel(readl(SW_INT_ENABLE_REG2) & ~(1<<irq), SW_INT_ENABLE_REG2);
- writel(readl(SW_INT_MASK_REG2) | (1 << irq), SW_INT_MASK_REG2);
- }
- }
- static void sw_irq_unmask(struct irq_data *irqd)
- {
- unsigned int irq = irqd->irq;
- if(irq < 32){
- writel(readl(SW_INT_ENABLE_REG0) | (1<<irq), SW_INT_ENABLE_REG0);
- writel(readl(SW_INT_MASK_REG0) & ~(1 << irq), SW_INT_MASK_REG0);
- if(irq == SW_INT_IRQNO_ENMI) /* must clear pending bit when enabled */
- writel((1 << SW_INT_IRQNO_ENMI), SW_INT_IRQ_PENDING_REG0);
- } else if(irq < 64){
- irq -= 32;
- writel(readl(SW_INT_ENABLE_REG1) | (1<<irq), SW_INT_ENABLE_REG1);
- writel(readl(SW_INT_MASK_REG1) & ~(1 << irq), SW_INT_MASK_REG1);
- } else if(irq < 96){
- irq -= 64;
- writel(readl(SW_INT_ENABLE_REG2) | (1<<irq), SW_INT_ENABLE_REG2);
- writel(readl(SW_INT_MASK_REG2) & ~(1 << irq), SW_INT_MASK_REG2);
- }
- }
- static struct irq_chip sw_vic_chip = {
- .name = "sw_vic",
- .irq_ack = sw_irq_ack,
- .irq_mask = sw_irq_mask,
- .irq_unmask = sw_irq_unmask,
- };
- void __init sw_core_init_irq(void)
- {
- u32 i = 0;
- /* Disable & clear all interrupts */
- writel(0, SW_INT_ENABLE_REG0);
- writel(0, SW_INT_ENABLE_REG1);
- writel(0, SW_INT_ENABLE_REG2);
- writel(0xffffffff, SW_INT_MASK_REG0);
- writel(0xffffffff, SW_INT_MASK_REG1);
- writel(0xffffffff, SW_INT_MASK_REG2);
- writel(0xffffffff, SW_INT_IRQ_PENDING_REG0);
- writel(0xffffffff, SW_INT_IRQ_PENDING_REG1);
- writel(0xffffffff, SW_INT_IRQ_PENDING_REG2);
- writel(0xffffffff, SW_INT_FIQ_PENDING_REG0);
- writel(0xffffffff, SW_INT_FIQ_PENDING_REG1);
- writel(0xffffffff, SW_INT_FIQ_PENDING_REG2);
- /*enable protection mode*/
- writel(0x01, SW_INT_PROTECTION_REG);
- /*config the external interrupt source type*/
- writel(0x00, SW_INT_NMI_CTRL_REG);
- for (i = SW_INT_START; i < SW_INT_END; i++) {
- irq_set_chip(i, &sw_vic_chip);
- irq_set_handler(i, handle_level_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
- }
- /**
- * Global vars definitions
- *
- */
- static void sun5i_restart(char mode, const char *cmd)
- {
- /* use watch-dog to reset system */
- #define WATCH_DOG_CTRL_REG (SW_VA_TIMERC_IO_BASE + 0x0094)
- *(volatile unsigned int *)WATCH_DOG_CTRL_REG = 0;
- __delay(100000);
- *(volatile unsigned int *)WATCH_DOG_CTRL_REG |= 2;
- while(1) {
- __delay(100);
- *(volatile unsigned int *)WATCH_DOG_CTRL_REG |= 1;
- }
- }
- static void timer_set_mode(enum clock_event_mode mode, struct clock_event_device *clk)
- {
- volatile u32 ctrl;
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- pr_info("timer2: Periodic Mode\n");
- writel(TMR_INTER_VAL, SW_TIMER2_INTVAL_REG); /* interval (999+1) */
- ctrl = readl(SW_TIMER2_CTL_REG);
- ctrl &= ~(1<<7); /* Continuous mode */
- ctrl |= 1; /* Enable this timer */
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- pr_info("timer2: Oneshot Mode\n");
- ctrl = readl(SW_TIMER2_CTL_REG);
- ctrl |= (1<<7); /* Single mode */
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- default:
- ctrl = readl(SW_TIMER2_CTL_REG);
- ctrl &= ~(1<<0); /* Disable timer0 */
- break;
- }
- writel(ctrl, SW_TIMER2_CTL_REG);
- }
- /* Useless when periodic mode */
- static int timer_set_next_event(unsigned long evt, struct clock_event_device *unused)
- {
- volatile u32 ctrl;
- /* clear any pending before continue */
- ctrl = readl(SW_TIMER2_CTL_REG);
- writel(evt, SW_TIMER2_CNTVAL_REG);
- ctrl |= (1<<1);
- writel(ctrl, SW_TIMER2_CTL_REG);
- writel(ctrl | 0x1, SW_TIMER2_CTL_REG);
- return 0;
- }
- #if (0)
- #define IPIPE_DBG(format,args...) printk("[IPIPE] "format,##args)
- #define IPIPE_ERR(format,args...) printk("[IPIPE] "format,##args)
- #else
- #define IPIPE_DBG(...)
- #define IPIPE_ERR(...)
- #endif
- #ifdef CONFIG_IPIPE
- /* ***********************************************
- The IPIPE TIMER
- *********************************************** */
- void ipipe_ns_delay( u32 ns);
- /*
- * Reprogram the timer
- */
- static int sun5i_set_timer0(unsigned long evt, void *timer)
- {
- IPIPE_DBG("sun5i_set_timer0()\n");
- volatile u32 val = 0;
- val = readl(SW_TIMER0_CTL_REG);
- if( (val & 0x1) == 1)
- {
- val &= ~(0x1); /* stop the timer */
- writel(val, SW_TIMER0_CTL_REG);
- ipipe_ns_delay(80); // wait for hardware synchronisation ?
- }
- /* set the timer */
- writel( evt, SW_TIMER0_INTVAL_REG);// no reason to add it
- writel( evt, SW_TIMER0_CNTVAL_REG);
- /* start the timer */
- val |= 0x1<<1; // reload!
- writel(val, SW_TIMER0_CTL_REG);
- val |= 0x1 ; // start
- writel(val, SW_TIMER0_CTL_REG);
- return 0;
- }
- /*
- * IRQ handler for the timer.
- */
- static void sun5i_ack_timer0(void)
- {
- IPIPE_DBG("sun5i_ack_timer0()\n");
- writel(1<<0, SW_TIMER_INT_STA_REG);
- }
- static void sun5i_request_timer0(struct ipipe_timer *timer, int steal)
- {
- IPIPE_DBG("sun5i_request_timer0()\n");
- /* Set timer on - Enable interrupt. */
- volatile u32 val = 0;
- /* set clock source to PLL6/6 */
- val = readl(SW_TIMER0_CTL_REG);
- val &= ~(0x07<<4);
- val &= ~(0x03<<2);
- val |= (2<<2) ;// PLL6/6 = 100 MHz
- val &= ~(1<<1); // no autoload
- val |= 1<<7; // single mode.
- writel(val, SW_TIMER0_CTL_REG);
- __delay( 50 );
- sun5i_ack_timer0();
- /* Enable timer0 interrupt */
- val = readl(SW_TIMER_INT_CTL_REG);
- val |= (1<<0);
- writel(val, SW_TIMER_INT_CTL_REG);
- }
- static void sun5i_release_timer0(struct ipipe_timer *timer)
- {
- IPIPE_DBG("sun5i_release_timer0()\n");
- volatile u32 val = 0;
- /* Disable timer0 interrupt. */
- val = readl(SW_TIMER_INT_CTL_REG);
- val &= ~(1<<0);
- writel(val, SW_TIMER_INT_CTL_REG);
- }
- static struct ipipe_timer sun5i_itimer = {
- .irq = SW_INT_IRQNO_TIMER0 ,
- .request = sun5i_request_timer0,
- .set = sun5i_set_timer0,
- .ack = sun5i_ack_timer0,
- .release = sun5i_release_timer0,
- .name = "sun5i_timer0",
- .rating = 340 ,
- .freq = 300000000 ,
- .min_delay_ticks = 1 ,
- // .cpumask = ,
- };
- /* ***********************************************
- The IPIPE CLOCK
- *********************************************** */
- static struct __ipipe_tscinfo tsc_info = {
- .type = IPIPE_TSC_TYPE_FREERUNNING_COUNTDOWN ,
- .freq = 300000000 , // 100 MHz
- .counter_vaddr = SW_TIMER1_CNTVAL_REG,
- .u = {
- {
- .counter_paddr = SW_TIMER1_CNTVAL_REG - SW_VA_TIMERC_IO_BASE + SW_PA_TIMERC_IO_BASE ,
- .mask = 0xffffffff,
- },
- },
- };
- void ipipe_ns_delay( u32 ns)
- {
- IPIPE_DBG("ipipe_ns_delay()\n");
- volatile u32 val ;
- volatile u32 val0 ;
- volatile i;
- val0 = readl( SW_TIMER1_CNTVAL_REG);
- i = ns * 10 ; // correct for a proc abble to do up to 10 loop per nanos ...
- ns = ( ns * ( tsc_info.freq / 1000 ) )/1000000 +1; // now number of cycles
- if( val0 > ns )
- {
- ns = val0 - ns ;
- for(; i > 0 ; i--)
- {
- val = readl( SW_TIMER1_CNTVAL_REG);
- if(( val <= ns ) || ( val > val0 )) return;
- };
- }
- else {
- ns = ( 0xffffffff - ns ) + val0 ;
- for(; i > 0 ; i--)
- {
- val = readl( SW_TIMER1_CNTVAL_REG);
- if(( val <= ns ) && ( val > val0 )) return;
- };
- }
- }
- void sun5i_ipipe_tsc_timer1_init( void )
- {
- IPIPE_DBG("sun5i_ipipe_tsc_timer1_init()\n");
- /* Set timer on */
- volatile u32 val = 0;
- /* set clock source to PLL6/6 */
- val = readl(SW_TIMER1_CTL_REG);
- val &= ~(0x1); // stop timer
- val &= ~(0x07<<4); // clear divisor
- val &= ~(0x03<<2); // clear source
- val &= ~(0x1<<7); // continous mode
- val |= (2<<2) ; // PLL6/6 = 100 MHz
- val |= (0<<4) ; // DIV/0
- writel(val, SW_TIMER1_CTL_REG);
- /* set value */
- writel( tsc_info.u.mask, SW_TIMER1_INTVAL_REG);
- /* start and auto reload */
- __delay(50); // wait for hardware synchronisation
- val = readl(SW_TIMER1_CTL_REG);
- val |= 1 | (1<<1);
- writel(val, SW_TIMER1_CTL_REG);
- }
- /* ***********************************************
- The IPIPE IRQ
- *********************************************** */
- /* ***********************************************
- Register IPIPE
- *********************************************** */
- void sun5i_ipipe_init( void )
- {
- IPIPE_DBG("sun5i_ipipe_init()\n");
- ipipe_timer_register(&sun5i_itimer); // register timer
- sun5i_ipipe_tsc_timer1_init();
- __ipipe_tsc_register(&tsc_info); // register clock
- }
- #endif /* CONFIG_IPIPE */
- static struct clock_event_device timer2_clockevent = {
- .name = "timer2",
- .shift = 32,
- .rating = 300,
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = timer_set_mode,
- .set_next_event = timer_set_next_event,
- };
- static irqreturn_t sw_timer_interrupt(int irq, void *dev_id)
- {
- struct clock_event_device *evt = (struct clock_event_device *)dev_id;
- #ifdef CONFIG_IPIPE
- __ipipe_tsc_update();
- #endif /* CONFIG_IPIPE */
- writel((1<<2), SW_TIMER_INT_STA_REG);
- /*
- * timer_set_next_event will be called only in ONESHOT mode
- */
- evt->event_handler(evt);
- return IRQ_HANDLED;
- }
- static struct irqaction sw_timer_irq = {
- .name = "timer2",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = sw_timer_interrupt,
- .dev_id = &timer2_clockevent,
- .irq = SW_INT_IRQNO_TIMER2,
- };
- static void __init sw_timer_init(void)
- {
- int ret;
- volatile u32 val = 0;
- writel(TMR_INTER_VAL, SW_TIMER2_INTVAL_REG);
- /* set clock sourch to HOSC, 16 pre-division */
- val = readl(SW_TIMER2_CTL_REG);
- val &= ~(0x07<<4);
- val &= ~(0x03<<2);
- val |= (4<<4) | (1<<2); // 24 MHz DIV/16 = 1.5 MHz
- writel(val, SW_TIMER2_CTL_REG);
- /* set mode to auto reload */
- val = readl(SW_TIMER2_CTL_REG);
- val |= (1<<1);
- writel(val, SW_TIMER2_CTL_REG);
- ret = setup_irq(SW_INT_IRQNO_TIMER2, &sw_timer_irq);
- if (ret) {
- pr_warning("failed to setup irq %d\n", SW_INT_IRQNO_TIMER2);
- }
- /* Enable time0 interrupt */
- val = readl(SW_TIMER_INT_CTL_REG);
- val |= (1<<2);
- writel(val, SW_TIMER_INT_CTL_REG);
- timer2_clockevent.mult = div_sc(SYS_TIMER_CLKSRC/SYS_TIMER_SCAL, NSEC_PER_SEC, timer2_clockevent.shift);
- timer2_clockevent.max_delta_ns = clockevent_delta2ns(0xff, &timer2_clockevent);
- timer2_clockevent.min_delta_ns = clockevent_delta2ns(0x1, &timer2_clockevent);
- timer2_clockevent.cpumask = cpumask_of(0);
- timer2_clockevent.irq = sw_timer_irq.irq;
- clockevents_register_device(&timer2_clockevent);
- #ifdef CONFIG_IPIPE
- sun5i_ipipe_init();
- #endif
- }
- struct sys_timer sw_sys_timer = {
- .init = sw_timer_init,
- };
- extern void __init sw_pdev_init(void);
- void __init sw_core_init(void)
- {
- sw_pdev_init();
- }
- enum sw_ic_ver sw_get_ic_ver(void)
- {
- volatile u32 val = readl(SW_VA_TIMERC_IO_BASE + 0x13c);
- val = (val >> 6) & 0x3;
- if (val == 0x3) {
- return MAGIC_VER_B;
- }
- return MAGIC_VER_A;
- }
- EXPORT_SYMBOL(sw_get_ic_ver);
- MACHINE_START(SUN5I, "sun5i")
- .atag_offset = 0x100,
- .timer = &sw_sys_timer,
- #ifdef CONFIG_SUNXI_MALI_RESERVED_MEM
- .fixup = sunxi_mali_core_fixup,
- #endif
- .map_io = sw_core_map_io,
- .init_early = NULL,
- .init_irq = sw_core_init_irq,
- .init_machine = sw_core_init,
- .reserve = sw_core_reserve,
- .restart = sun5i_restart,
- MACHINE_END
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement