/* * puma5_core.c * Description: * Architecture specific stuff. * * * * Copyright (C) 2008, Texas Instruments, Incorporated * * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope 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 #include #include #ifdef CONFIG_HIGH_RES_TIMERS #include #include #endif /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ #include #include #include #include #include #include #include #include #include #include #include #include /*--- #define CONFIG_PUMA_DEBUG_TIMER ---*/ #ifdef CONFIG_PUMA_DEBUG_TIMER #define DBGT(args...) printk(KERN_ERR args) #else #define DBGT(args...) #endif void arch_init_irq(void); extern void timer_tick(void); extern int ti_avalanche_setup(void); static unsigned int c55_mem_start; static unsigned int puma_cpu_cycles_factor; struct NO_OPERSYS_MEM_DESC_T no_OperSys_memory_desc[eNO_OperSys_END]; #ifdef CONFIG_HIGH_RES_TIMERS static void config_timer2(void); #endif static struct map_desc puma5_io_desc[] __initdata = { { .virtual = IO_VIRT, .pfn = __phys_to_pfn(IO_PHY), .length = IO_SIZE, .type = MT_DEVICE }, { .virtual = EMIF3E_VIRT, .pfn = __phys_to_pfn(EMIF3E_PHY), .length = EMIF3E_SIZE, .type = MT_DEVICE }, { .virtual = FLASH_0_VIRT, .pfn = __phys_to_pfn(FLASH_0_PHY), .length = FLASH_0_SIZE, .type = MT_DEVICE }, { .virtual = FLASH_1_VIRT, .pfn = __phys_to_pfn(FLASH_1_PHY), .length = FLASH_1_SIZE, .type = MT_DEVICE }, { .virtual = MM_SPI_0_VIRT, .pfn = __phys_to_pfn(MM_SPI_0_PHY), .length = MM_SPI_0_SIZE, .type = MT_MEMORY }, { .virtual = MM_SPI_1_VIRT, .pfn = __phys_to_pfn(MM_SPI_1_PHY), .length = MM_SPI_1_SIZE, .type = MT_MEMORY }, { .virtual = INTC_VIRT, .pfn = __phys_to_pfn(INTC_PHY), .length = INTC_SIZE, .type = MT_DEVICE_NONSHARED }, #if defined(CONFIG_MACH_PUMA5_VOLCANO) { .virtual = VOLCANO_VIRT, .pfn = __phys_to_pfn(VOLCANO_PHY), .length = VOLCANO_SIZE, .type = MT_DEVICE } #endif }; void busy_delay(unsigned long delay){ volatile unsigned int tmp; unsigned long i, _delay; _delay = delay * 100000; for (i = 0; i < _delay; i++){ tmp = 0; } } static void __init puma5_map_io(void) { iotable_init(puma5_io_desc, ARRAY_SIZE(puma5_io_desc)); } #define TIMER16_CNTRL_PRESCALE_ENABLE 0x8000 #define TIMER16_CNTRL_PRESCALE 0x003C #define TIMER16_CNTRL_MODE 0x0002 #define TIMER16_MINPRESCALE 2 #define TIMER16_MAXPRESCALE 8192 #define TIMER16_PRESCALE_DEFAULT 0x09 #define TIMER16_MIN_LOAD_VALUE 1 #define TIMER16_MAX_LOAD_VALUE 0xFFFF #define MHZ 1000000 /* set min clock divisor to a little higher value * so that we are not close to the edge. * so multiply by factor 2 */ #define TIMER16_MAX_CLK_DIVISOR (TIMER16_MAX_LOAD_VALUE * TIMER16_MAXPRESCALE) #define TIMER16_MIN_CLK_DIVISOR (TIMER16_MIN_LOAD_VALUE * TIMER16_MINPRESCALE * 2) typedef struct { volatile u32 ctrl_reg; /* Timer Control Register */ volatile u32 load_reg; /* Timer Load value register */ volatile u32 count_reg; /* Timer count register */ volatile u32 intr_reg; /* Timer Interrupt register */ } puma_timer_regs_t; typedef enum { TIMER16_STATUS_STOP = 0, TIMER16_STATUS_START } puma_timer_status; extern unsigned int system_rev; #ifdef CONFIG_HIGH_RES_TIMERS /**************************************************************************** * FUNCTION: puma_config_timer **************************************************************************** * Description: The routine is called to configure the timer mode and * time period (in micro seconds). * returns prescale ***************************************************************************/ int puma_config_timer(u32 base_address, u32 refclk_freq, PAL_SYS_TIMER16_MODE_T mode, u32 usec) { volatile puma_timer_regs_t *p_timer; u32 prescale; u32 count; u32 ctrl_reg; u32 refclk_mhz = (refclk_freq / MHZ); DBGT("[%s] base_address=%#x\n", __FUNCTION__, base_address); DBGT("[%s] refclk_freq=%dMHZ\n", __FUNCTION__, refclk_mhz); DBGT("[%s] usecs=%d\n", __FUNCTION__, usec); if ((base_address == 0) || (usec == 0)){ printk(KERN_ERR "[%s] base_address oder usec 0", __FUNCTION__); return -1; } if ((mode != TIMER16_CNTRL_ONESHOT) && (mode != TIMER16_CNTRL_AUTOLOAD)){ printk(KERN_ERR "[%s] Error: Mode AUTOLOAD oder ONESHOT wird benoetigt", __FUNCTION__); return -1; } /* The min time period is 1 usec and since the reference clock freq is always going to be more than "min" divider value, minimum value is not checked. Check the max time period that can be derived from the timer in micro-seconds */ if (usec > ((TIMER16_MAX_CLK_DIVISOR) / refclk_mhz)) { printk(KERN_ERR "[%s] input argument speed out of range\n", __FUNCTION__); return -1; } p_timer = (puma_timer_regs_t *) (base_address); count = refclk_mhz * usec; DBGT("[%s] initial_count=%d\n", __FUNCTION__, count); /*------------------------------------------------------------------------------------*\ * Experimentell ermittelt, da Doku unvollstaendig: * * T = ( 2 ^ (prescale + 1 ) ) * COUNT / f_timer_clock \*------------------------------------------------------------------------------------*/ for (prescale = 0; prescale < 12; prescale++) { count = count >> 1; if (count <= TIMER16_MAX_LOAD_VALUE) { DBGT("[%s] count < TIMER16_MAX_LOAD_VALUE -> break\n", __FUNCTION__); break; } } /*write the load counter value */ DBGT("[%s] final_count=%d\n", __FUNCTION__, count); p_timer->load_reg = count; /* write prescalar and mode to control reg */ ctrl_reg = mode | TIMER16_CNTRL_PRESCALE_ENABLE | (prescale << 2); DBGT("[%s] prescale=%d\n", __FUNCTION__, prescale); p_timer->ctrl_reg = ctrl_reg; busy_delay(1000); return (int)prescale; } static void config_timer2(void) { volatile puma_timer_regs_t *p_timer; u32 ctrl_reg; u32 base_address = AVALANCHE_TIMER2_BASE; p_timer = (puma_timer_regs_t *) (base_address); DBGT("[%s] base_address=%#x\n", __FUNCTION__, base_address); /*write the load counter value */ p_timer->load_reg = TIMER16_MAX_LOAD_VALUE; /*-----------------------------------------------------------------*\ * write prescalar and mode to control reg * TIMER16_PRESCALE_DEFAULT = 9 * ==> * Tcycle = 671ms, * Taufloesung = 10,2us \*-----------------------------------------------------------------*/ ctrl_reg = TIMER16_CNTRL_AUTOLOAD | TIMER16_CNTRL_PRESCALE_ENABLE |(TIMER16_PRESCALE_DEFAULT << 2); p_timer->ctrl_reg = ctrl_reg; busy_delay(1000); } /**************************************************************************** * FUNCTION: puma_timer_ctrl **************************************************************************** * Description: The routine is called to start/stop the timer * ***************************************************************************/ void puma_timer_ctrl(u32 base_address, puma_timer_status status) { volatile puma_timer_regs_t *p_timer; if (base_address) { p_timer = (puma_timer_regs_t *) (base_address); if (status == TIMER16_CTRL_START) { p_timer->ctrl_reg |= TIMER16_CTRL_START; /*--- DBGT("[%d:START]\n", base_address == AVALANCHE_TIMER0_BASE ? 0 : 2); ---*/ } else { p_timer->ctrl_reg &= ~(TIMER16_CTRL_START); /*--- DBGT("[%d:STOP]\n", base_address == AVALANCHE_TIMER0_BASE ? 0 : 2); ---*/ } } } /**************************************************************************** * FUNCTION: puma_timer_read **************************************************************************** * Description: The routine is called to read the current value of timer. * ***************************************************************************/ static cycle_t timer_read(void) { static spinlock_t tlock = SPIN_LOCK_UNLOCKED; static cycle_t overflow_timer_value; static unsigned int last_t; volatile puma_timer_regs_t *p_timer; unsigned long flags = 0; cycle_t timer_value; register unsigned int t; p_timer = (puma_timer_regs_t *)(AVALANCHE_TIMER2_BASE); spin_lock_irqsave(&tlock, flags); t = (p_timer->load_reg & 0xffff) - (p_timer->count_reg & 0xffff); if(t < last_t) overflow_timer_value += 1 << 16; last_t = t; spin_unlock_irqrestore(&tlock, flags); timer_value = (cycle_t)t | overflow_timer_value; return timer_value; } /* * clocksource */ static struct clocksource clocksource_puma = { .name = "cs_puma", .rating = 300, .read = timer_read, .mask = CLOCKSOURCE_MASK(64), .shift = 16, .flags = CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES }; static int puma_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { volatile puma_timer_regs_t *p_timer; p_timer = (puma_timer_regs_t *)(AVALANCHE_TIMER0_BASE); /* First stop the timer */ p_timer->ctrl_reg &= ~(TIMER16_CTRL_START); /* Load the value being passed */ p_timer->load_reg = cycles; /* Now start the timer */ p_timer->ctrl_reg |= TIMER16_CTRL_START; return 0; } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void puma_timer_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { volatile puma_timer_regs_t *p_timer; p_timer = (puma_timer_regs_t *)(AVALANCHE_TIMER0_BASE); switch (mode) { case CLOCK_EVT_MODE_PERIODIC: /* write mode to control reg */ p_timer->ctrl_reg |= TIMER16_CNTRL_AUTOLOAD; break; case CLOCK_EVT_MODE_ONESHOT: /* write mode to control reg */ p_timer->ctrl_reg &= ~(TIMER16_CNTRL_AUTOLOAD); break; case CLOCK_EVT_MODE_SHUTDOWN: /* stop the timer */ p_timer->ctrl_reg &= ~(TIMER16_CTRL_START); break; default: DBGT("[0:default]"); break; } } /* * clockevent */ static struct clock_event_device clockevent_puma = { .name = "ce_puma", .features = CLOCK_EVT_FEAT_ONESHOT, .shift = 32, .set_next_event = puma_timer_set_next_event, .set_mode = puma_timer_set_mode, }; #endif /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void puma_cpu_cycle_init(void) { union __performance_monitor_control C; write_secure_debug_enable_register(0, 1); C.Register = read_p15_performance_monitor_control(); C.Bits.CycleCounterDivider = 1; /*--- / 64 ---*/ C.Bits.EnableCounters = 1; write_p15_performance_monitor_control(C.Register); DBGT(KERN_ERR"%s: enable cycle_count performance-monitor-register: %x\n", __func__, read_p15_performance_monitor_control()); } cycles_t get_puma_cpu_cycles(void) { /*--- return clocksource_puma.read() * puma_cpu_cycles_factor; ---*/ return read_p15_cycle_counter() << 5; /*--- konform mit MIPS-Takt ---*/ } EXPORT_SYMBOL(get_puma_cpu_cycles); #ifdef CONFIG_HIGH_RES_TIMERS unsigned int timer_irq_count = 0; static irqreturn_t puma_timer0_interrupt(int irq, void *dev_id) { volatile puma_timer_regs_t *p_timer; if(clockevent_puma.event_handler) { clockevent_puma.event_handler(&clockevent_puma); } p_timer = (puma_timer_regs_t *)(AVALANCHE_TIMER0_BASE); if(p_timer->ctrl_reg & TIMER16_CNTRL_AUTOLOAD) { p_timer->ctrl_reg |= TIMER16_CTRL_START; } timer_irq_count++; return IRQ_HANDLED; } #else /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ static irqreturn_t puma_timer0_interrupt(int irq, void *dev_id) { write_seqlock(&xtime_lock); timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } #endif /*--- #else ---*/ /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ static struct irqaction puma_timer0_irq = { .name = "Puma5 Timer Tick", .flags = IRQF_DISABLED | IRQF_TIMER |IRQF_IRQPOLL , /* POLL hinzugefuegt (wie bei omap1)*/ .handler = puma_timer0_interrupt, }; #ifdef CONFIG_HIGH_RES_TIMERS /*-------------------------------------------------------------------------------------*\ Euklidias Algo Wenn b > a: eine Schleifenoperation mehr !!! ret = 0: wenn a oder b == 0 \*-------------------------------------------------------------------------------------*/ static unsigned int ggT(unsigned int a, unsigned int b) { unsigned int Rest; if(a == 0) { return 0; } Rest = b; while(Rest) { b = Rest; Rest = a % b; a = b; } return b; } /* * Set up timer interrupt, and return the current time in seconds. */ static void __init puma5_timer_init(void) { int timer_clk; int scale_timer0; int scale_timer2; int cpu = smp_processor_id(); unsigned int puma_cpu_clock; int exp_prescale_timer0; /* update PG info */ system_rev = *(volatile unsigned int*)(AVALANCHE_PG_INFO_REG); system_rev &= AVALANCHE_PG_INFO_MASK; system_rev >>= AVALANCHE_PG_INFO_SHIFT; ti_avalanche_setup(); puma_cpu_cycle_init(); /*-------------------------------------------------------------------------------------*\ * get the input clock frequency * Input_Clock_Frequency = VBUS_Frequency = 100MHz * (Unterscheiden sich nicht wie im Puma Manual S.24-2 beschrieben) \*-------------------------------------------------------------------------------------*/ timer_clk = PAL_sysClkcGetFreq(CLKC_VBUS); /* 100MHz */ DBGT("[%s] vbus_clock=%d \n", __FUNCTION__, timer_clk); DBGT("[%s] HZ=%d \n", __FUNCTION__, HZ); /*--------------------------------------------------------------------------------------*\ * Timer 0 * berechne den benoetigten prescale-exponenten um eine MaxTimerPeriod von 16/HZ * einzurichten \*--------------------------------------------------------------------------------------*/ PAL_sysResetCtrl(AVALANCHE_TIMER0_RESET_BIT, OUT_OF_RESET); exp_prescale_timer0 = puma_config_timer(AVALANCHE_TIMER0_BASE, timer_clk, TIMER16_CNTRL_AUTOLOAD, (int)((16.0 / (float)(HZ)) * 1000000.0)); puma_timer_ctrl(AVALANCHE_TIMER0_BASE, TIMER16_CTRL_START); setup_irq(AVALANCHE_TIMER_0_INT, &puma_timer0_irq); /*--------------------------------------------------------------------------------------*\ * Timer 2 \*--------------------------------------------------------------------------------------*/ PAL_sysResetCtrl(AVALANCHE_TIMER2_RESET_BIT, OUT_OF_RESET); config_timer2(); puma_timer_ctrl(AVALANCHE_TIMER2_BASE, TIMER16_CTRL_START); /*--------------------------------------------------------------------------------------*\ * Get the scaler value for dividing timer frequency \*--------------------------------------------------------------------------------------*/ scale_timer2 = ( 2 * ( 1 << TIMER16_PRESCALE_DEFAULT ) ); /*--------------------------------------------------------------------------------------*\ * setup and register clocksource (Timer 2) \*--------------------------------------------------------------------------------------*/ clocksource_puma.mult = clocksource_hz2mult(timer_clk/scale_timer2, clocksource_puma.shift); DBGT("Mult = %u\n", clocksource_puma.mult); if (clocksource_register(&clocksource_puma)) printk(KERN_ERR "%s: can't register clocksource!\n", clocksource_puma.name); puma_cpu_clock = puma_get_clock(avm_clock_id_cpu); #if 0 puma_cpu_cycles_factor = (unsigned int)(((u64)puma_cpu_clock / 2 * (u64)clocksource_puma.mult) >> (clocksource_puma.shift)) / 1000 ; #else { unsigned int timer2_clk, teiler = ggT(puma_cpu_clock, timer_clk); puma_cpu_clock /= teiler, timer2_clk = timer_clk / teiler; puma_cpu_cycles_factor = (unsigned int)((puma_cpu_clock / 2 * scale_timer2) / timer2_clk); } #endif/*--- #else ---*/ DBGT("[%s] puma_cpu_clock=%d, factor=%d\n", __FUNCTION__, puma_cpu_clock, puma_cpu_cycles_factor); /*--------------------------------------------------------------------------------------*\ * setup and register clockevent (Timer 0) \*--------------------------------------------------------------------------------------*/ scale_timer0 = 2 * ( 1 << exp_prescale_timer0 ); if (scale_timer2 < scale_timer0 ) { printk(KERN_ERR "[%s] Warning: (scale_timer2 < scale_timer0) => NoHz-Timer might exceed clocksource-cycle \n", __FUNCTION__); } /*--- static inline unsigned long div_sc(unsigned long ticks, unsigned long nsec, int shift) ---*/ clockevent_puma.mult = div_sc(timer_clk/scale_timer0, NSEC_PER_SEC, clockevent_puma.shift); clockevent_puma.max_delta_ns = clockevent_delta2ns(0xfffe, &clockevent_puma); clockevent_puma.min_delta_ns = clockevent_delta2ns(1, &clockevent_puma); clockevent_puma.cpumask = cpumask_of_cpu(cpu); /*--- DBGT("puma5_timer_init: current_cpu=%i, cpumask_of_cpu=0x%lx \n", cpu, clockevent_puma.cpumask); ---*/ busy_delay(1000); clockevents_register_device(&clockevent_puma); printk(KERN_INFO " Puma5 Timer0 and HRES Timer2 initialized\n"); debug_plldiv_regs(); } #else /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ static void __init puma5_timer_init(void) { int timer_clk; /* update PG info */ system_rev = *(volatile unsigned int*)(AVALANCHE_PG_INFO_REG); system_rev &= AVALANCHE_PG_INFO_MASK; system_rev >>= AVALANCHE_PG_INFO_SHIFT; ti_avalanche_setup(); /* get the input clock frequency */ timer_clk = PAL_sysClkcGetFreq(CLKC_VBUS); /* timer 0 - enable timer and auto load, and go off every 1 ms */ PAL_sysResetCtrl(AVALANCHE_TIMER0_RESET_BIT, OUT_OF_RESET); PAL_sysTimer16SetParams(AVALANCHE_TIMER0_BASE, timer_clk, TIMER16_CNTRL_AUTOLOAD, (int)((1.0/(float)(HZ)) * 1000000.0)); PAL_sysTimer16Ctrl(AVALANCHE_TIMER0_BASE, TIMER16_CTRL_START); setup_irq(AVALANCHE_TIMER_0_INT, &puma_timer0_irq); printk(KERN_INFO " Puma5 Timer0 initialized - not using HRES_TIMER\n"); } #endif /*--- #else ---*/ /*--- #ifdef CONFIG_HIGH_RES_TIMERS ---*/ static struct sys_timer puma5_timer = { .init = puma5_timer_init, }; /*------------------------------------------------------------------------------------------------------------------*\ * Timer Config END \*------------------------------------------------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ int prom_c55_get_base_memory(unsigned int *base, unsigned int *len) { if(len)*len = CONFIG_ARM_PUMA_C55_MEMORY * (1 << 10); if(base)*base = c55_mem_start; return 0; } EXPORT_SYMBOL(prom_c55_get_base_memory); #if 0 /* This API is used to allocate specified size of memory for the * specified module (DSP) from the reserved region. Currently size * of reserved region is decided at compile time using Kconfig variable */ int avalanche_alloc_no_OperSys_memory(AVALANCHE_NO_OPERSYS_MOD_T mod, unsigned int size, unsigned int *phys_start) { unsigned long cookie; int ret = 0; if(mod >= eNO_OperSys_END) return -1; PAL_osProtectEntry(PAL_OSPROTECT_INTERRUPT, &cookie); /* If the memory was already allocated then simply return it */ if(no_OperSys_memory_desc[mod].reserved) { *phys_start = no_OperSys_memory_desc[mod].phys_start; goto topmem_done; } /* 32-bit align */ size = ((size + 0x3) & (~0x3)); /* we do not have that much reserved memory */ if(size > no_linux_mem_size) { ret = -1; goto topmem_done; } no_linux_mem_size -= size; switch(mod) { case eNO_OperSys_VDSP: no_OperSys_memory_desc[mod].reserved = 1; no_OperSys_memory_desc[mod].phys_start = no_linux_mem_start; *phys_start = no_linux_mem_start; no_linux_mem_start += size; break; #if 0 /* This block might be required for future SOCs */ case eNO_OperSys_DSLDSP: no_linux_mem_last -= size; *phys_start = no_linux_mem_last; no_OperSys_memory_desc[mod].reserved = 1; no_OperSys_memory_desc[mod].phys_start = no_linux_mem_last; #endif default: ret = -1; } topmem_done: PAL_osProtectExit(PAL_OSPROTECT_INTERRUPT, cookie); return ret; } EXPORT_SYMBOL(avalanche_alloc_no_OperSys_memory); #endif /* variable used by vlynq */ unsigned int avalanche_mem_size; EXPORT_SYMBOL(avalanche_mem_size); static void __init puma5_fixup(struct machine_desc *desc, struct tag *tag, char **cmdline, struct meminfo *mi) { for (; tag->hdr.size; tag = tag_next(tag)) { if (tag->hdr.tag == ATAG_MEM) { unsigned long size; unsigned long start; /*--- tag->u.mem.size = 64 << 20; ---*/ /*--- tag->u.mem.start = 0x80000000; ---*/ size = tag->u.mem.size; start = tag->u.mem.start; mi->bank[mi->nr_banks].start = PAGE_ALIGN(start); mi->bank[mi->nr_banks].size = size & PAGE_MASK; mi->bank[mi->nr_banks].node = PHYS_TO_NID(start); printk("bank[%d] start %lx size %lx node %x\n",mi->nr_banks, mi->bank[mi->nr_banks].start, mi->bank[mi->nr_banks].size, mi->bank[mi->nr_banks].node); /*--- tag->u.mem.size = size; ---*/ /* dsp memory starts where normal memory ends */ /*--- no_linux_mem_start = start + size; ---*/ avalanche_mem_size += size; mi->nr_banks += 1; break; } } } /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static int var_is_in_area(unsigned long test, unsigned long range_min, unsigned long range_max) { if((test >= range_min) && (test < range_max)) { return 1; } return 0; } extern void _text, _stext, _etext, __data_start, _end, __init_begin, __init_end; #define ALIGN_16MBYTE(addr) ((addr) & ~((16 * SZ_1M) - 1)) /*--------------------------------------------------------------------------------*\ * keine Ueberschneidung mit Kernel! \*--------------------------------------------------------------------------------*/ struct resource *puma5_alloc_c55_code(unsigned long ramstart, unsigned long ramend) { #if defined(CONFIG_ARM_PUMA_C55_MEMORY) && (CONFIG_ARM_PUMA_C55_MEMORY != 0) static struct resource c55_pram; unsigned long c55_codsize = SZ_1K * CONFIG_ARM_PUMA_C55_MEMORY; unsigned long kcode_start = virt_to_phys(&_text); unsigned long kcode_end = virt_to_phys(&_etext - 1); unsigned long kdata_start = virt_to_phys(&__data_start); unsigned long kdata_end = virt_to_phys(&_end - 1); ramend = ALIGN_16MBYTE(ramend + 1); c55_mem_start = 0; while(ramend > (ramstart + c55_codsize)) { c55_mem_start = ramend - c55_codsize; if(!var_is_in_area(c55_mem_start, kcode_start, kcode_end) && !var_is_in_area(c55_mem_start + c55_codsize, kcode_start, kcode_end) && !var_is_in_area(c55_mem_start, kdata_start, kdata_end) && !var_is_in_area(c55_mem_start + c55_codsize, kdata_start, kdata_end)) { break; } ramend = ALIGN_16MBYTE(ramend-1); c55_mem_start = 0; } if(c55_mem_start) { printk("[c55] c55_mem_start = 0x%x\n", c55_mem_start); c55_pram.name = "c55 text"; c55_pram.start = c55_mem_start; c55_pram.end = c55_pram.start + c55_codsize - 1; c55_pram.flags = IORESOURCE_MEM | IORESOURCE_BUSY; return &c55_pram; } #endif/*--- #if defined(CONFIG_ARM_PUMA_C55_MEMORY) && (CONFIG_ARM_PUMA_C55_MEMORY != 0) ---*/ return NULL; } #if defined(CONFIG_AVALANCHE_ADAM2) || defined(CONFIG_AVALANCHE_EVA) struct puma5_cmd { char cmd[COMMAND_LINE_SIZE]; }; /* set default memory size to 64M */ #ifndef MEM_SIZE #define MEM_SIZE (64*1024*1024) #endif static struct init_tags { struct tag_header hdr1; struct tag_core core; struct tag_header hdr2; struct tag_mem32 mem; struct tag_header hdr3; struct puma5_cmd cmd; struct tag_header hdr4; } puma5_command_line_tag __initdata = { { tag_size(tag_core), ATAG_CORE }, { 1, PAGE_SIZE, 0xff }, { tag_size(tag_mem32), ATAG_MEM }, { MEM_SIZE, PHYS_OFFSET }, { tag_size(puma5_cmd), ATAG_CMDLINE }, { { 0 } }, { 0, ATAG_NONE } }; #endif /*--- #if defined(CONFIG_AVALANCHE_ADAM2) || defined(CONFIG_AVALANCHE_EVA) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined(CONFIG_AVALANCHE_ADAM2) void __init volcano_adam2_init(void) { int i, count, end_idx; char *cmdline; char *cmd_ptr; char *end_mark = "-PM5-"; cmdline = (char*) AVALANCHE_CMDLINE_BASE; memcpy(puma5_command_line_tag.cmd.cmd, cmdline, COMMAND_LINE_SIZE); cmd_ptr = puma5_command_line_tag.cmd.cmd; count = 0; end_idx = 0; for(i=0; i= strlen(end_mark)) break; } else { if(cmd_ptr[i] == 0x0) cmd_ptr[i] = ' '; count = i; end_idx = 0; } } for(i=count; i= strlen(end_mark)) break; } else { if(cmd_ptr[i] == 0x0) cmd_ptr[i] = ' '; count = i; end_idx = 0; } } /*--- for(i=count; i> 18) & 0xfffc, #if defined(CONFIG_AVALANCHE_U_BOOT) .boot_params = PUMA5_BOOT_PARAM_BASE, #endif #if defined(CONFIG_AVALANCHE_EVA) .boot_params = PUMA5_BOOT_PARAM_BASE, /*--- .boot_params = (unsigned long)&puma5_command_line_tag, ---*/ #endif #if defined(CONFIG_AVALANCHE_ADAM2) .boot_params = (unsigned long)&puma5_command_line_tag, #endif .map_io = puma5_map_io, .init_irq = arch_init_irq, .timer = &puma5_timer, .fixup = puma5_fixup, MACHINE_END /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int avm_reset_status(void) { return 0x0; /*--- immer poweron ---*/ } EXPORT_SYMBOL(avm_reset_status); /*--- Kernel-Schnittstelle für das neue LED-Modul ---*/ enum _led_event { /* DUMMY DEFINITION */ LastEvent = 0 }; int (*led_event_action)(int, enum _led_event , unsigned int ) = NULL; EXPORT_SYMBOL(led_event_action);