diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 19:11:51 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-11 19:11:51 -0700 |
commit | 1ef3e36251e4edc77a48967d015a87ca3c4283ea (patch) | |
tree | 2ee6c869d752c13a56ee2259d115210135f5d5de /arch/blackfin/kernel | |
parent | c634920abaf9c0a93266a57beff6fce9d3852cb2 (diff) | |
parent | bbf275f092b1b2a9bc8a504500ec387f9ddff859 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/blackfin-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/blackfin-2.6: (74 commits)
Blackfin serial driver: pending a unique anomaly id, tie the break flood issue to ANOMALY_05000230
blackfin enable arbitary speed serial setting
Blackfin arch: Remove cruft - CONFIG_DEBUG_SERIAL_EARLY_INIT and DEBUG_KERNEL_START
Blackfin arch: fix typo in register name
Blackfin arch: trim the Blackfin arch MAINTAINERS list
Blackfin arch: fix bug libstdc++ calling writev with an iovec containing { NULL, 0 } fails on Blackfin
Blackfin arch: Export strcpy - occasionally get module link failures otherwise
Blackfin arch: the load address is not safe to point to as a workaround for ANOMALY 05000281
Blackfin arch: show_mem can not be marked as init, since it is called during OOM condition
Blackfin arch: flush/inv the correct range when using write back cache and fix bugs find by dmacopy
Blackfin arch: update kgdb patch
Blackfin arch: Comply with revised Anomaly Workarounds for BF533 05000311 and BF561 05000323
Blackfin arch: Print out debug info, as early as possible
Blackfin arch: Enable earlyprintk earlier - so any error after our interrupt tables are set up will print out
Blackfin arch: fix endless loop bug when a double fault happens
Blackfin arch: Initial patch to add earlyprintk support
Blackfin arch: add TWIx_REGBASE and SPIx_REGBASE to specific CPU header files, use the new REGBASE for board platform resources
Blackfin arch: modify the insX/outsX and dma_insX/dma_outsX to be compatible with other archs
Blackfin arch: add more common defines for output sections
Blackfin arch: cleanup IO and DMA_IO API function definitions according to other arches
...
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r-- | arch/blackfin/kernel/Makefile | 5 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_dma_5xx.c | 81 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_gpio.c | 549 | ||||
-rw-r--r-- | arch/blackfin/kernel/bfin_ksyms.c | 1 | ||||
-rw-r--r-- | arch/blackfin/kernel/cacheinit.c | 5 | ||||
-rw-r--r-- | arch/blackfin/kernel/cplbinit.c | 7 | ||||
-rw-r--r-- | arch/blackfin/kernel/early_printk.c | 214 | ||||
-rw-r--r-- | arch/blackfin/kernel/irqchip.c | 12 | ||||
-rw-r--r-- | arch/blackfin/kernel/process.c | 28 | ||||
-rw-r--r-- | arch/blackfin/kernel/ptrace.c | 24 | ||||
-rw-r--r-- | arch/blackfin/kernel/reboot.c | 78 | ||||
-rw-r--r-- | arch/blackfin/kernel/setup.c | 90 | ||||
-rw-r--r-- | arch/blackfin/kernel/traps.c | 110 | ||||
-rw-r--r-- | arch/blackfin/kernel/vmlinux.lds.S | 48 |
14 files changed, 1001 insertions, 251 deletions
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index f429ebc3a96..8aeb6066b19 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -7,11 +7,10 @@ extra-y := init_task.o vmlinux.lds obj-y := \ entry.o process.o bfin_ksyms.o ptrace.o setup.o signal.o \ sys_bfin.o time.o traps.o irqchip.o dma-mapping.o flat.o \ - fixed_code.o cplbinit.o cacheinit.o + fixed_code.o cplbinit.o cacheinit.o reboot.o bfin_gpio.o -obj-$(CONFIG_BF53x) += bfin_gpio.o -obj-$(CONFIG_BF561) += bfin_gpio.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_BFIN_DMA_5XX) += bfin_dma_5xx.o obj-$(CONFIG_DUAL_CORE_TEST_MODULE) += dualcore_test.o obj-$(CONFIG_KGDB) += kgdb.o +obj-$(CONFIG_EARLY_PRINTK) += early_printk.o diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 7cf02f02a1d..e19164fb4cd 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -73,6 +73,11 @@ static int __init blackfin_dma_init(void) /* Mark MEMDMA Channel 0 as requested since we're using it internally */ dma_ch[CH_MEM_STREAM0_DEST].chan_status = DMA_CHANNEL_REQUESTED; dma_ch[CH_MEM_STREAM0_SRC].chan_status = DMA_CHANNEL_REQUESTED; + +#if defined(CONFIG_DEB_DMA_URGENT) + bfin_write_EBIU_DDRQUE(bfin_read_EBIU_DDRQUE() + | DEB1_URGENT | DEB2_URGENT | DEB3_URGENT); +#endif return 0; } @@ -265,10 +270,23 @@ void set_dma_next_desc_addr(unsigned int channel, unsigned long addr) dma_ch[channel].regs->next_desc_ptr = addr; SSYNC(); - pr_debug("set_dma_start_addr() : END\n"); + pr_debug("set_dma_next_desc_addr() : END\n"); } EXPORT_SYMBOL(set_dma_next_desc_addr); +void set_dma_curr_desc_addr(unsigned int channel, unsigned long addr) +{ + pr_debug("set_dma_curr_desc_addr() : BEGIN \n"); + + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->curr_desc_ptr = addr; + SSYNC(); + pr_debug("set_dma_curr_desc_addr() : END\n"); +} +EXPORT_SYMBOL(set_dma_curr_desc_addr); + void set_dma_x_count(unsigned int channel, unsigned short x_count) { BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE @@ -345,6 +363,16 @@ void set_dma_sg(unsigned int channel, struct dmasg *sg, int nr_sg) } EXPORT_SYMBOL(set_dma_sg); +void set_dma_curr_addr(unsigned int channel, unsigned long addr) +{ + BUG_ON(!(dma_ch[channel].chan_status != DMA_CHANNEL_FREE + && channel < MAX_BLACKFIN_DMA_CHANNEL)); + + dma_ch[channel].regs->curr_addr_ptr = addr; + SSYNC(); +} +EXPORT_SYMBOL(set_dma_curr_addr); + /*------------------------------------------------------------------------------ * Get the DMA status of a specific DMA channel from the system. *-----------------------------------------------------------------------------*/ @@ -408,6 +436,10 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) blackfin_dcache_flush_range((unsigned int)src, (unsigned int)(src + size)); + if ((unsigned long)dest < memory_end) + blackfin_dcache_invalidate_range((unsigned int)dest, + (unsigned int)(dest + size)); + bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); if ((unsigned long)src < (unsigned long)dest) @@ -515,6 +547,8 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) } } + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)) ; @@ -524,9 +558,6 @@ static void *__dma_memcpy(void *dest, const void *src, size_t size) bfin_write_MDMA_S0_CONFIG(0); bfin_write_MDMA_D0_CONFIG(0); - if ((unsigned long)dest < memory_end) - blackfin_dcache_invalidate_range((unsigned int)dest, - (unsigned int)(dest + size)); local_irq_restore(flags); return dest; @@ -555,13 +586,14 @@ void *safe_dma_memcpy(void *dest, const void *src, size_t size) } EXPORT_SYMBOL(safe_dma_memcpy); -void dma_outsb(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsb(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -576,6 +608,8 @@ void dma_outsb(void __iomem *addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -588,10 +622,13 @@ void dma_outsb(void __iomem *addr, const void *buf, unsigned short len) EXPORT_SYMBOL(dma_outsb); -void dma_insb(const void __iomem *addr, void *buf, unsigned short len) +void dma_insb(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); bfin_write_MDMA_D0_X_COUNT(len); @@ -606,7 +643,7 @@ void dma_insb(const void __iomem *addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_8); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_8); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -619,13 +656,14 @@ void dma_insb(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insb); -void dma_outsw(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsw(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -640,6 +678,8 @@ void dma_outsw(void __iomem *addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -651,10 +691,13 @@ void dma_outsw(void __iomem *addr, const void *buf, unsigned short len) } EXPORT_SYMBOL(dma_outsw); -void dma_insw(const void __iomem *addr, void *buf, unsigned short len) +void dma_insw(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(short)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -670,7 +713,7 @@ void dma_insw(const void __iomem *addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_16); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_16); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); @@ -683,13 +726,14 @@ void dma_insw(const void __iomem *addr, void *buf, unsigned short len) } EXPORT_SYMBOL(dma_insw); -void dma_outsl(void __iomem *addr, const void *buf, unsigned short len) +void dma_outsl(unsigned long addr, const void *buf, unsigned short len) { unsigned long flags; local_irq_save(flags); - blackfin_dcache_flush_range((unsigned int)buf, (unsigned int)(buf) + len); + blackfin_dcache_flush_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); bfin_write_MDMA_D0_START_ADDR(addr); bfin_write_MDMA_D0_X_COUNT(len); @@ -704,6 +748,8 @@ void dma_outsl(void __iomem *addr, const void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32); + SSYNC(); + while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); bfin_write_MDMA_D0_IRQ_STATUS(DMA_DONE | DMA_ERR); @@ -715,10 +761,13 @@ void dma_outsl(void __iomem *addr, const void *buf, unsigned short len) } EXPORT_SYMBOL(dma_outsl); -void dma_insl(const void __iomem *addr, void *buf, unsigned short len) +void dma_insl(unsigned long addr, void *buf, unsigned short len) { unsigned long flags; + blackfin_dcache_invalidate_range((unsigned int)buf, + (unsigned int)(buf) + len * sizeof(long)); + local_irq_save(flags); bfin_write_MDMA_D0_START_ADDR(buf); @@ -734,7 +783,7 @@ void dma_insl(const void __iomem *addr, void *buf, unsigned short len) bfin_write_MDMA_S0_CONFIG(DMAEN | WDSIZE_32); bfin_write_MDMA_D0_CONFIG(WNR | DI_EN | DMAEN | WDSIZE_32); - blackfin_dcache_invalidate_range((unsigned int)buf, (unsigned int)(buf) + len); + SSYNC(); while (!(bfin_read_MDMA_D0_IRQ_STATUS() & DMA_DONE)); diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 5d488ef965c..3fe0cd49e8d 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -7,7 +7,7 @@ * Description: GPIO Abstraction Layer * * Modified: - * Copyright 2006 Analog Devices Inc. + * Copyright 2007 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * @@ -28,9 +28,9 @@ */ /* -* Number BF537/6/4 BF561 BF533/2/1 +* Number BF537/6/4 BF561 BF533/2/1 BF549/8/4/2 * -* GPIO_0 PF0 PF0 PF0 +* GPIO_0 PF0 PF0 PF0 PA0...PJ13 * GPIO_1 PF1 PF1 PF1 * GPIO_2 PF2 PF2 PF2 * GPIO_3 PF3 PF3 PF3 @@ -80,6 +80,7 @@ * GPIO_47 PH15 PF47 */ +#include <linux/delay.h> #include <linux/module.h> #include <linux/err.h> #include <asm/blackfin.h> @@ -87,6 +88,36 @@ #include <asm/portmux.h> #include <linux/irq.h> +#if ANOMALY_05000311 || ANOMALY_05000323 +enum { + AWA_data = SYSCR, + AWA_data_clear = SYSCR, + AWA_data_set = SYSCR, + AWA_toggle = SYSCR, + AWA_maska = UART_SCR, + AWA_maska_clear = UART_SCR, + AWA_maska_set = UART_SCR, + AWA_maska_toggle = UART_SCR, + AWA_maskb = UART_GCTL, + AWA_maskb_clear = UART_GCTL, + AWA_maskb_set = UART_GCTL, + AWA_maskb_toggle = UART_GCTL, + AWA_dir = SPORT1_STAT, + AWA_polar = SPORT1_STAT, + AWA_edge = SPORT1_STAT, + AWA_both = SPORT1_STAT, +#if ANOMALY_05000311 + AWA_inen = TIMER_ENABLE, +#elif ANOMALY_05000323 + AWA_inen = DMA1_1_CONFIG, +#endif +}; + /* Anomaly Workaround */ +#define AWA_DUMMY_READ(name) bfin_read16(AWA_ ## name) +#else +#define AWA_DUMMY_READ(...) do { } while (0) +#endif + #ifdef BF533_FAMILY static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { (struct gpio_port_t *) FIO_FLAG_D, @@ -116,11 +147,31 @@ static struct gpio_port_t *gpio_bankb[gpio_bank(MAX_BLACKFIN_GPIOS)] = { }; #endif +#ifdef BF548_FAMILY +static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { + (struct gpio_port_t *)PORTA_FER, + (struct gpio_port_t *)PORTB_FER, + (struct gpio_port_t *)PORTC_FER, + (struct gpio_port_t *)PORTD_FER, + (struct gpio_port_t *)PORTE_FER, + (struct gpio_port_t *)PORTF_FER, + (struct gpio_port_t *)PORTG_FER, + (struct gpio_port_t *)PORTH_FER, + (struct gpio_port_t *)PORTI_FER, + (struct gpio_port_t *)PORTJ_FER, +}; +#endif + static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS + 16)]; -char *str_ident = NULL; -#define RESOURCE_LABEL_SIZE 16 +#define MAX_RESOURCES 256 +#define RESOURCE_LABEL_SIZE 16 + +struct str_ident { + char name[RESOURCE_LABEL_SIZE]; +} *str_ident; + #ifdef CONFIG_PM static unsigned short wakeup_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; @@ -141,21 +192,32 @@ static unsigned int sic_iwr_irqs[gpio_bank(MAX_BLACKFIN_GPIOS)] = {IRQ_PROG0_INT #endif /* CONFIG_PM */ +#if defined(BF548_FAMILY) +inline int check_gpio(unsigned short gpio) +{ + if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 + || gpio == GPIO_PH14 || gpio == GPIO_PH15 + || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 + || gpio > MAX_BLACKFIN_GPIOS) + return -EINVAL; + return 0; +} +#else inline int check_gpio(unsigned short gpio) { if (gpio >= MAX_BLACKFIN_GPIOS) return -EINVAL; return 0; } +#endif static void set_label(unsigned short ident, const char *label) { if (label && str_ident) { - strncpy(str_ident + ident * RESOURCE_LABEL_SIZE, label, + strncpy(str_ident[ident].name, label, RESOURCE_LABEL_SIZE); - str_ident[ident * RESOURCE_LABEL_SIZE + - RESOURCE_LABEL_SIZE - 1] = 0; + str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; } } @@ -164,14 +226,13 @@ static char *get_label(unsigned short ident) if (!str_ident) return "UNKNOWN"; - return (str_ident[ident * RESOURCE_LABEL_SIZE] ? - (str_ident + ident * RESOURCE_LABEL_SIZE) : "UNKNOWN"); + return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); } static int cmp_label(unsigned short ident, const char *label) { if (label && str_ident) - return strncmp(str_ident + ident * RESOURCE_LABEL_SIZE, + return strncmp(str_ident[ident].name, label, strlen(label)); else return -EINVAL; @@ -181,50 +242,84 @@ static int cmp_label(unsigned short ident, const char *label) static void port_setup(unsigned short gpio, unsigned short usage) { if (!check_gpio(gpio)) { - if (usage == GPIO_USAGE) { + if (usage == GPIO_USAGE) *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); - } else + else *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); SSYNC(); } } +#elif defined(BF548_FAMILY) +static void port_setup(unsigned short gpio, unsigned short usage) +{ + if (usage == GPIO_USAGE) + gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); + else + gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); + SSYNC(); +} #else # define port_setup(...) do { } while (0) #endif #ifdef BF537_FAMILY - -#define PMUX_LUT_RES 0 -#define PMUX_LUT_OFFSET 1 -#define PMUX_LUT_ENTRIES 41 -#define PMUX_LUT_SIZE 2 - -static unsigned short port_mux_lut[PMUX_LUT_ENTRIES][PMUX_LUT_SIZE] = { - {P_PPI0_D13, 11}, {P_PPI0_D14, 11}, {P_PPI0_D15, 11}, - {P_SPORT1_TFS, 11}, {P_SPORT1_TSCLK, 11}, {P_SPORT1_DTPRI, 11}, - {P_PPI0_D10, 10}, {P_PPI0_D11, 10}, {P_PPI0_D12, 10}, - {P_SPORT1_RSCLK, 10}, {P_SPORT1_RFS, 10}, {P_SPORT1_DRPRI, 10}, - {P_PPI0_D8, 9}, {P_PPI0_D9, 9}, {P_SPORT1_DRSEC, 9}, - {P_SPORT1_DTSEC, 9}, {P_TMR2, 8}, {P_PPI0_FS3, 8}, {P_TMR3, 7}, - {P_SPI0_SSEL4, 7}, {P_TMR4, 6}, {P_SPI0_SSEL5, 6}, {P_TMR5, 5}, - {P_SPI0_SSEL6, 5}, {P_UART1_RX, 4}, {P_UART1_TX, 4}, {P_TMR6, 4}, - {P_TMR7, 4}, {P_UART0_RX, 3}, {P_UART0_TX, 3}, {P_DMAR0, 3}, - {P_DMAR1, 3}, {P_SPORT0_DTSEC, 1}, {P_SPORT0_DRSEC, 1}, - {P_CAN0_RX, 1}, {P_CAN0_TX, 1}, {P_SPI0_SSEL7, 1}, - {P_SPORT0_TFS, 0}, {P_SPORT0_DTPRI, 0}, {P_SPI0_SSEL2, 0}, - {P_SPI0_SSEL3, 0} +static struct { + unsigned short res; + unsigned short offset; +} port_mux_lut[] = { + {.res = P_PPI0_D13, .offset = 11}, + {.res = P_PPI0_D14, .offset = 11}, + {.res = P_PPI0_D15, .offset = 11}, + {.res = P_SPORT1_TFS, .offset = 11}, + {.res = P_SPORT1_TSCLK, .offset = 11}, + {.res = P_SPORT1_DTPRI, .offset = 11}, + {.res = P_PPI0_D10, .offset = 10}, + {.res = P_PPI0_D11, .offset = 10}, + {.res = P_PPI0_D12, .offset = 10}, + {.res = P_SPORT1_RSCLK, .offset = 10}, + {.res = P_SPORT1_RFS, .offset = 10}, + {.res = P_SPORT1_DRPRI, .offset = 10}, + {.res = P_PPI0_D8, .offset = 9}, + {.res = P_PPI0_D9, .offset = 9}, + {.res = P_SPORT1_DRSEC, .offset = 9}, + {.res = P_SPORT1_DTSEC, .offset = 9}, + {.res = P_TMR2, .offset = 8}, + {.res = P_PPI0_FS3, .offset = 8}, + {.res = P_TMR3, .offset = 7}, + {.res = P_SPI0_SSEL4, .offset = 7}, + {.res = P_TMR4, .offset = 6}, + {.res = P_SPI0_SSEL5, .offset = 6}, + {.res = P_TMR5, .offset = 5}, + {.res = P_SPI0_SSEL6, .offset = 5}, + {.res = P_UART1_RX, .offset = 4}, + {.res = P_UART1_TX, .offset = 4}, + {.res = P_TMR6, .offset = 4}, + {.res = P_TMR7, .offset = 4}, + {.res = P_UART0_RX, .offset = 3}, + {.res = P_UART0_TX, .offset = 3}, + {.res = P_DMAR0, .offset = 3}, + {.res = P_DMAR1, .offset = 3}, + {.res = P_SPORT0_DTSEC, .offset = 1}, + {.res = P_SPORT0_DRSEC, .offset = 1}, + {.res = P_CAN0_RX, .offset = 1}, + {.res = P_CAN0_TX, .offset = 1}, + {.res = P_SPI0_SSEL7, .offset = 1}, + {.res = P_SPORT0_TFS, .offset = 0}, + {.res = P_SPORT0_DTPRI, .offset = 0}, + {.res = P_SPI0_SSEL2, .offset = 0}, + {.res = P_SPI0_SSEL3, .offset = 0}, }; static void portmux_setup(unsigned short per, unsigned short function) { - u16 y, muxreg, offset; + u16 y, offset, muxreg; - for (y = 0; y < PMUX_LUT_ENTRIES; y++) { - if (port_mux_lut[y][PMUX_LUT_RES] == per) { + for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) { + if (port_mux_lut[y].res == per) { /* SET PORTMUX REG */ - offset = port_mux_lut[y][PMUX_LUT_OFFSET]; + offset = port_mux_lut[y].offset; muxreg = bfin_read_PORT_MUX(); if (offset != 1) { @@ -238,18 +333,42 @@ static void portmux_setup(unsigned short per, unsigned short function) } } } +#elif defined(BF548_FAMILY) +inline void portmux_setup(unsigned short portno, unsigned short function) +{ + u32 pmux; + + pmux = gpio_array[gpio_bank(portno)]->port_mux; + + pmux &= ~(0x3 << (2 * gpio_sub_n(portno))); + pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); + gpio_array[gpio_bank(portno)]->port_mux = pmux; +} + +inline u16 get_portmux(unsigned short portno) +{ + u32 pmux; + + pmux = gpio_array[gpio_bank(portno)]->port_mux; + + return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); +} #else # define portmux_setup(...) do { } while (0) #endif +#ifndef BF548_FAMILY static void default_gpio(unsigned short gpio) { unsigned short bank, bitmask; + unsigned long flags; bank = gpio_bank(gpio); bitmask = gpio_bit(gpio); + local_irq_save(flags); + gpio_bankb[bank]->maska_clear = bitmask; gpio_bankb[bank]->maskb_clear = bitmask; SSYNC(); @@ -258,24 +377,32 @@ static void default_gpio(unsigned short gpio) gpio_bankb[bank]->polar &= ~bitmask; gpio_bankb[bank]->both &= ~bitmask; gpio_bankb[bank]->edge &= ~bitmask; + AWA_DUMMY_READ(edge); + local_irq_restore(flags); + } +#else +# define default_gpio(...) do { } while (0) +#endif static int __init bfin_gpio_init(void) { - - str_ident = kzalloc(RESOURCE_LABEL_SIZE * 256, GFP_KERNEL); - if (!str_ident) + str_ident = kcalloc(MAX_RESOURCES, + sizeof(struct str_ident), GFP_KERNEL); + if (str_ident == NULL) return -ENOMEM; + memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident)); + printk(KERN_INFO "Blackfin GPIO Controller\n"); return 0; } - arch_initcall(bfin_gpio_init); +#ifndef BF548_FAMILY /*********************************************************** * * FUNCTIONS: Blackfin General Purpose Ports Access Functions @@ -305,6 +432,7 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ else \ gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ + AWA_DUMMY_READ(name); \ local_irq_restore(flags); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); @@ -316,6 +444,22 @@ SET_GPIO(edge) SET_GPIO(both) +#if ANOMALY_05000311 || ANOMALY_05000323 +#define SET_GPIO_SC(name) \ +void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); \ + local_irq_save(flags); \ + if (arg) \ + gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ + else \ + gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ +} \ +EXPORT_SYMBOL(set_gpio_ ## name); +#else #define SET_GPIO_SC(name) \ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ { \ @@ -326,37 +470,20 @@ void set_gpio_ ## name(unsigned short gpio, unsigned short arg) \ gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); +#endif SET_GPIO_SC(maska) SET_GPIO_SC(maskb) - -#if defined(ANOMALY_05000311) -void set_gpio_data(unsigned short gpio, unsigned short arg) -{ - unsigned long flags; - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - local_irq_save(flags); - if (arg) - gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); - else - gpio_bankb[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); - bfin_read_CHIPID(); - local_irq_restore(flags); -} -EXPORT_SYMBOL(set_gpio_data); -#else SET_GPIO_SC(data) -#endif - -#if defined(ANOMALY_05000311) +#if ANOMALY_05000311 || ANOMALY_05000323 void set_gpio_toggle(unsigned short gpio) { unsigned long flags; BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio); - bfin_read_CHIPID(); + AWA_DUMMY_READ(toggle); local_irq_restore(flags); } #else @@ -371,13 +498,27 @@ EXPORT_SYMBOL(set_gpio_toggle); /*Set current PORT date (16-bit word)*/ +#if ANOMALY_05000311 || ANOMALY_05000323 #define SET_GPIO_P(name) \ void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \ { \ + unsigned long flags; \ + local_irq_save(flags); \ gpio_bankb[gpio_bank(gpio)]->name = arg; \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ } \ EXPORT_SYMBOL(set_gpiop_ ## name); +#else +#define SET_GPIO_P(name) \ +void set_gpiop_ ## name(unsigned short gpio, unsigned short arg) \ +{ \ + gpio_bankb[gpio_bank(gpio)]->name = arg; \ +} \ +EXPORT_SYMBOL(set_gpiop_ ## name); +#endif +SET_GPIO_P(data) SET_GPIO_P(dir) SET_GPIO_P(inen) SET_GPIO_P(polar) @@ -387,31 +528,30 @@ SET_GPIO_P(maska) SET_GPIO_P(maskb) -#if defined(ANOMALY_05000311) -void set_gpiop_data(unsigned short gpio, unsigned short arg) -{ - unsigned long flags; - local_irq_save(flags); - gpio_bankb[gpio_bank(gpio)]->data = arg; - bfin_read_CHIPID(); - local_irq_restore(flags); -} -EXPORT_SYMBOL(set_gpiop_data); -#else -SET_GPIO_P(data) -#endif - - - /* Get a specific bit */ - +#if ANOMALY_05000311 || ANOMALY_05000323 +#define GET_GPIO(name) \ +unsigned short get_gpio_ ## name(unsigned short gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + local_irq_save(flags); \ + ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + return ret; \ +} \ +EXPORT_SYMBOL(get_gpio_ ## name); +#else #define GET_GPIO(name) \ unsigned short get_gpio_ ## name(unsigned short gpio) \ { \ return (0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio))); \ } \ EXPORT_SYMBOL(get_gpio_ ## name); +#endif +GET_GPIO(data) GET_GPIO(dir) GET_GPIO(inen) GET_GPIO(polar) @@ -420,33 +560,31 @@ GET_GPIO(both) GET_GPIO(maska) GET_GPIO(maskb) - -#if defined(ANOMALY_05000311) -unsigned short get_gpio_data(unsigned short gpio) -{ - unsigned long flags; - unsigned short ret; - BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); - local_irq_save(flags); - ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->data >> gpio_sub_n(gpio)); - bfin_read_CHIPID(); - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(get_gpio_data); -#else -GET_GPIO(data) -#endif - /*Get current PORT date (16-bit word)*/ +#if ANOMALY_05000311 || ANOMALY_05000323 +#define GET_GPIO_P(name) \ +unsigned short get_gpiop_ ## name(unsigned short gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + local_irq_save(flags); \ + ret = (gpio_bankb[gpio_bank(gpio)]->name); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + return ret; \ +} \ +EXPORT_SYMBOL(get_gpiop_ ## name); +#else #define GET_GPIO_P(name) \ unsigned short get_gpiop_ ## name(unsigned short gpio) \ { \ return (gpio_bankb[gpio_bank(gpio)]->name);\ } \ EXPORT_SYMBOL(get_gpiop_ ## name); +#endif +GET_GPIO_P(data) GET_GPIO_P(dir) GET_GPIO_P(inen) GET_GPIO_P(polar) @@ -455,21 +593,6 @@ GET_GPIO_P(both) GET_GPIO_P(maska) GET_GPIO_P(maskb) -#if defined(ANOMALY_05000311) -unsigned short get_gpiop_data(unsigned short gpio) -{ - unsigned long flags; - unsigned short ret; - local_irq_save(flags); - ret = gpio_bankb[gpio_bank(gpio)]->data; - bfin_read_CHIPID(); - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(get_gpiop_data); -#else -GET_GPIO_P(data) -#endif #ifdef CONFIG_PM /*********************************************************** @@ -593,6 +716,8 @@ u32 gpio_pm_setup(void) } } + AWA_DUMMY_READ(maskb_set); + if (sic_iwr) return sic_iwr; else @@ -624,12 +749,99 @@ void gpio_pm_restore(void) gpio_bankb[bank]->maskb = gpio_bank_saved[bank].maskb; } + AWA_DUMMY_READ(maskb); } #endif +#endif /* BF548_FAMILY */ +/*********************************************************** +* +* FUNCTIONS: Blackfin Peripheral Resource Allocation +* and PortMux Setup +* +* INPUTS/OUTPUTS: +* per Peripheral Identifier +* label String +* +* DESCRIPTION: Blackfin Peripheral Resource Allocation and Setup API +* +* CAUTION: +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ + +#ifdef BF548_FAMILY +int peripheral_request(unsigned short per, const char *label) +{ + unsigned long flags; + unsigned short ident = P_IDENT(per); + + /* + * Don't cares are pins with only one dedicated function + */ + + if (per & P_DONTCARE) + return 0; + + if (!(per & P_DEFINED)) + return -ENODEV; + + if (check_gpio(ident) < 0) + return -EINVAL; + + local_irq_save(flags); + + if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { + printk(KERN_ERR + "%s: Peripheral %d is already reserved as GPIO by %s !\n", + __FUNCTION__, ident, get_label(ident)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + + if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { + + u16 funct = get_portmux(ident); + + /* + * Pin functions like AMC address strobes my + * be requested and used by several drivers + */ + + if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { + + /* + * Allow that the identical pin function can + * be requested from the same driver twice + */ + + if (cmp_label(ident, label) == 0) + goto anyway; + printk(KERN_ERR + "%s: Peripheral %d function %d is already reserved by %s !\n", + __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + } +anyway: + reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); + + portmux_setup(ident, P_FUNCT2MUX(per)); + port_setup(ident, PERIPHERAL_USAGE); + + local_irq_restore(flags); + set_label(ident, label); + + return 0; +} +EXPORT_SYMBOL(peripheral_request); +#else int peripheral_request(unsigned short per, const char *label) { @@ -680,7 +892,7 @@ int peripheral_request(unsigned short per, const char *label) printk(KERN_ERR "%s: Peripheral %d function %d is already" - "reserved by %s !\n", + " reserved by %s !\n", __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); dump_stack(); @@ -691,8 +903,6 @@ int peripheral_request(unsigned short per, const char *label) } anyway: - - portmux_setup(per, P_FUNCT2MUX(per)); port_setup(ident, PERIPHERAL_USAGE); @@ -704,6 +914,7 @@ anyway: return 0; } EXPORT_SYMBOL(peripheral_request); +#endif int peripheral_request_list(unsigned short per[], const char *label) { @@ -711,9 +922,15 @@ int peripheral_request_list(unsigned short per[], const char *label) int ret; for (cnt = 0; per[cnt] != 0; cnt++) { + ret = peripheral_request(per[cnt], label); - if (ret < 0) - return ret; + + if (ret < 0) { + for ( ; cnt > 0; cnt--) { + peripheral_free(per[cnt - 1]); + } + return ret; + } } return 0; @@ -748,6 +965,8 @@ void peripheral_free(unsigned short per) reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); + set_label(ident, "free"); + local_irq_restore(flags); } EXPORT_SYMBOL(peripheral_free); @@ -768,8 +987,8 @@ EXPORT_SYMBOL(peripheral_free_list); * FUNCTIONS: Blackfin GPIO Driver * * INPUTS/OUTPUTS: -* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS -* +* gpio PIO Number between 0 and MAX_BLACKFIN_GPIOS +* label String * * DESCRIPTION: Blackfin GPIO Driver API * @@ -787,17 +1006,39 @@ int gpio_request(unsigned short gpio, const char *label) local_irq_save(flags); + /* + * Allow that the identical GPIO can + * be requested from the same driver twice + * Do nothing and return - + */ + + if (cmp_label(gpio, label) == 0) { + local_irq_restore(flags); + return 0; + } + if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { - printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved!\n", gpio); + printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); dump_stack(); local_irq_restore(flags); return -EBUSY; } + if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { + printk(KERN_ERR + "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + dump_stack(); + local_irq_restore(flags); + return -EBUSY; + } + reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); local_irq_restore(flags); port_setup(gpio, GPIO_USAGE); + set_label(gpio, label); return 0; } @@ -823,10 +1064,57 @@ void gpio_free(unsigned short gpio) reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); + set_label(gpio, "free"); + local_irq_restore(flags); } EXPORT_SYMBOL(gpio_free); +#ifdef BF548_FAMILY +void gpio_direction_input(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); + gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_input); + +void gpio_direction_output(unsigned short gpio) +{ + unsigned long flags; + + BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); + + local_irq_save(flags); + gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); + gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio); + local_irq_restore(flags); +} +EXPORT_SYMBOL(gpio_direction_output); + +void gpio_set_value(unsigned short gpio, unsigned short arg) +{ + if (arg) + gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio); + else + gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio); + +} +EXPORT_SYMBOL(gpio_set_value); + +unsigned short gpio_get_value(unsigned short gpio) +{ + return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio))); +} +EXPORT_SYMBOL(gpio_get_value); + +#else + void gpio_direction_input(unsigned short gpio) { unsigned long flags; @@ -836,6 +1124,7 @@ void gpio_direction_input(unsigned short gpio) local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio); + AWA_DUMMY_READ(inen); local_irq_restore(flags); } EXPORT_SYMBOL(gpio_direction_input); @@ -849,6 +1138,28 @@ void gpio_direction_output(unsigned short gpio) local_irq_save(flags); gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio); + AWA_DUMMY_READ(dir); local_irq_restore(flags); } EXPORT_SYMBOL(gpio_direction_output); + +/* If we are booting from SPI and our board lacks a strong enough pull up, + * the core can reset and execute the bootrom faster than the resistor can + * pull the signal logically high. To work around this (common) error in + * board design, we explicitly set the pin back to GPIO mode, force /CS + * high, and wait for the electrons to do their thing. + * + * This function only makes sense to be called from reset code, but it + * lives here as we need to force all the GPIO states w/out going through + * BUG() checks and such. + */ +void bfin_gpio_reset_spi0_ssel1(void) +{ + u16 gpio = P_IDENT(P_SPI0_SSEL1); + + port_setup(gpio, GPIO_USAGE); + gpio_bankb[gpio_bank(gpio)]->data_set = gpio_bit(gpio); + udelay(1); +} + +#endif /*BF548_FAMILY */ diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index 70455949cfd..2198afe40f3 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -60,6 +60,7 @@ EXPORT_SYMBOL(csum_partial_copy); * their interface isn't gonna change any time soon now, so * it's OK to leave it out of version control. */ +EXPORT_SYMBOL(strcpy); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcmp); diff --git a/arch/blackfin/kernel/cacheinit.c b/arch/blackfin/kernel/cacheinit.c index 4d41a40e813..62cbba7364b 100644 --- a/arch/blackfin/kernel/cacheinit.c +++ b/arch/blackfin/kernel/cacheinit.c @@ -21,9 +21,10 @@ #include <asm/cacheflush.h> #include <asm/blackfin.h> +#include <asm/cplb.h> #include <asm/cplbinit.h> -#if defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_ICACHE) void bfin_icache_init(void) { unsigned long *table = icplb_table; @@ -44,7 +45,7 @@ void bfin_icache_init(void) } #endif -#if defined(CONFIG_BLKFIN_DCACHE) +#if defined(CONFIG_BFIN_DCACHE) void bfin_dcache_init(void) { unsigned long *table = dcplb_table; diff --git a/arch/blackfin/kernel/cplbinit.c b/arch/blackfin/kernel/cplbinit.c index bbdb403fcb5..f2db6a5e2b5 100644 --- a/arch/blackfin/kernel/cplbinit.c +++ b/arch/blackfin/kernel/cplbinit.c @@ -23,6 +23,7 @@ #include <linux/module.h> #include <asm/blackfin.h> +#include <asm/cplb.h> #include <asm/cplbinit.h> u_long icplb_table[MAX_CPLBS+1]; @@ -56,7 +57,7 @@ struct s_cplb { struct cplb_tab switch_d; }; -#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) static struct cplb_desc cplb_data[] = { { .start = 0, @@ -230,8 +231,8 @@ static void __fill_code_cplbtab(struct cplb_tab *t, int i, u32 a_start, u32 a_en cplb_data[i].psize, cplb_data[i].i_conf); } else { -#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) - if (i == SDRAM_KERN) { +#if defined(CONFIG_BFIN_ICACHE) + if (ANOMALY_05000263 && i == SDRAM_KERN) { fill_cplbtab(t, cplb_data[i].start, cplb_data[i].end, diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c new file mode 100644 index 00000000000..6ec518a8111 --- /dev/null +++ b/arch/blackfin/kernel/early_printk.c @@ -0,0 +1,214 @@ +/* + * File: arch/blackfin/kernel/early_printk.c + * Based on: arch/x86_64/kernel/early_printk.c + * Author: Robin Getz <rgetz@blackfin.uclinux.org + * + * Created: 14Aug2007 + * Description: allow a console to be used for early printk + * + * Modified: + * Copyright 2004-2007 Analog Devices Inc. + * + * Bugs: Enter bugs at http://blackfin.uclinux.org/ + * + * 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. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/console.h> +#include <linux/string.h> +#include <asm/blackfin.h> +#include <asm/irq_handler.h> +#include <asm/early_printk.h> + +#ifdef CONFIG_SERIAL_BFIN +extern struct console *bfin_earlyserial_init(unsigned int port, + unsigned int cflag); +#endif + +static struct console *early_console; + +/* Default console */ +#define DEFAULT_PORT 0 +#define DEFAULT_CFLAG CS8|B57600 + +/* Default console for early crashes */ +#define DEFAULT_EARLY_PORT "serial,uart0,57600" + +#ifdef CONFIG_SERIAL_CORE +/* What should get here is "0,57600" */ +static struct console * __init earlyserial_init(char *buf) +{ + int baud, bit; + char parity; + unsigned int serial_port = DEFAULT_PORT; + unsigned int cflag = DEFAULT_CFLAG; + + serial_port = simple_strtoul(buf, &buf, 10); + buf++; + + cflag = 0; + baud = simple_strtoul(buf, &buf, 10); + switch (baud) { + case 1200: + cflag |= B1200; + break; + case 2400: + cflag |= B2400; + break; + case 4800: + cflag |= B4800; + break; + case 9600: + cflag |= B9600; + break; + case 19200: + cflag |= B19200; + break; + case 38400: + cflag |= B38400; + break; + case 115200: + cflag |= B115200; + break; + default: + cflag |= B57600; + } + + parity = buf[0]; + buf++; + switch (parity) { + case 'e': + cflag |= PARENB; + break; + case 'o': + cflag |= PARODD; + break; + } + + bit = simple_strtoul(buf, &buf, 10); + switch (bit) { + case 5: + cflag |= CS5; + break; + case 6: + cflag |= CS5; + break; + case 7: + cflag |= CS5; + break; + default: + cflag |= CS8; + } + +#ifdef CONFIG_SERIAL_BFIN + return bfin_earlyserial_init(serial_port, cflag); +#else + return NULL; +#endif + +} +#endif + +int __init setup_early_printk(char *buf) +{ + + /* Crashing in here would be really bad, so check both the var + and the pointer before we start using it + */ + if (!buf) + return 0; + + if (!*buf) + return 0; + + if (early_console != NULL) + return 0; + +#ifdef CONFIG_SERIAL_BFIN + /* Check for Blackfin Serial */ + if (!strncmp(buf, "serial,uart", 11)) { + buf += 11; + early_console = earlyserial_init(buf); + } +#endif +#ifdef CONFIG_FB + /* TODO: add framebuffer console support */ +#endif + + if (likely(early_console)) { + early_console->flags |= CON_BOOT; + + register_console(early_console); + printk(KERN_INFO "early printk enabled on %s%d\n", + early_console->name, + early_console->index); + } + + return 0; +} + +/* + * Set up a temporary Event Vector Table, so if something bad happens before + * the kernel is fully started, it doesn't vector off into somewhere we don't + * know + */ + +asmlinkage void __init init_early_exception_vectors(void) +{ + SSYNC(); + + /* cannot program in software: + * evt0 - emulation (jtag) + * evt1 - reset + */ + bfin_write_EVT2(early_trap); + bfin_write_EVT3(early_trap); + bfin_write_EVT5(early_trap); + bfin_write_EVT6(early_trap); + bfin_write_EVT7(early_trap); + bfin_write_EVT8(early_trap); + bfin_write_EVT9(early_trap); + bfin_write_EVT10(early_trap); + bfin_write_EVT11(early_trap); + bfin_write_EVT12(early_trap); + bfin_write_EVT13(early_trap); + bfin_write_EVT14(early_trap); + bfin_write_EVT15(early_trap); + CSYNC(); + + /* Set all the return from interupt, exception, NMI to a known place + * so if we do a RETI, RETX or RETN by mistake - we go somewhere known + * Note - don't change RETS - we are in a subroutine, or + * RETE - since it might screw up if emulator is attached + */ + asm("\tRETI = %0; RETX = %0; RETN = %0;\n" + : : "p"(early_trap)); + +} + +asmlinkage void __init early_trap_c(struct pt_regs *fp, void *retaddr) +{ + /* This can happen before the uart is initialized, so initialize + * the UART now + */ + if (likely(early_console == NULL)) + setup_early_printk(DEFAULT_EARLY_PORT); + + dump_bfin_regs(fp, retaddr); + dump_bfin_trace_buffer(); + + panic("Died early"); +} + +early_param("earlyprintk", setup_early_printk); diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c index 1fc001c7abd..73647c15877 100644 --- a/arch/blackfin/kernel/irqchip.c +++ b/arch/blackfin/kernel/irqchip.c @@ -34,6 +34,7 @@ #include <linux/kallsyms.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <asm/trace.h> static unsigned long irq_err_count; static spinlock_t irq_controller_lock; @@ -97,9 +98,8 @@ int show_interrupts(struct seq_file *p, void *v) */ #ifdef CONFIG_DO_IRQ_L1 -asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)__attribute__((l1_text)); +__attribute__((l1_text)) #endif - asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs; @@ -144,4 +144,12 @@ void __init init_IRQ(void) } init_arch_irq(); + +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + /* Now that evt_ivhw is set up, turn this on */ + trace_buff_offset = 0; + bfin_write_TBUFCTL(BFIN_TRACE_ON); + printk(KERN_INFO "Hardware Trace expanded to %ik\n", + 1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN); +#endif } diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 6a7aefe4834..9124467651c 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -134,31 +134,6 @@ void cpu_idle(void) } } -void machine_restart(char *__unused) -{ -#if defined(CONFIG_BLKFIN_CACHE) - bfin_write_IMEM_CONTROL(0x01); - SSYNC(); -#endif - bfin_reset(); - /* Dont do anything till the reset occurs */ - while (1) { - SSYNC(); - } -} - -void machine_halt(void) -{ - for (;;) - asm volatile ("idle"); -} - -void machine_power_off(void) -{ - for (;;) - asm volatile ("idle"); -} - void show_regs(struct pt_regs *regs) { printk(KERN_NOTICE "\n"); @@ -420,7 +395,8 @@ void finish_atomic_sections (struct pt_regs *regs) #if defined(CONFIG_ACCESS_CHECK) int _access_ok(unsigned long addr, unsigned long size) { - + if (size == 0) + return 1; if (addr > (addr + size)) return 0; if (segment_eq(get_fs(), KERNEL_DS)) diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index ed800c7456d..64ce5fea860 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -44,6 +44,7 @@ #include <asm/processor.h> #include <asm/asm-offsets.h> #include <asm/dma.h> +#include <asm/fixed_code.h> #define MAX_SHARED_LIBS 3 #define TEXT_OFFSET 0 @@ -169,6 +170,9 @@ static inline int is_user_addr_valid(struct task_struct *child, && start + len <= (unsigned long)sraml->addr + sraml->length) return 0; + if (start >= FIXED_CODE_START && start + len <= FIXED_CODE_END) + return 0; + return -EIO; } @@ -215,9 +219,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = sizeof(tmp); } else #endif - copied = - access_process_vm(child, addr + add, &tmp, - sizeof(tmp), 0); + if (addr + add >= FIXED_CODE_START + && addr + add + sizeof(tmp) <= FIXED_CODE_END) { + memcpy(&tmp, (const void *)(addr + add), sizeof(tmp)); + copied = sizeof(tmp); + } else + copied = access_process_vm(child, addr + add, &tmp, + sizeof(tmp), 0); pr_debug("ptrace: copied size %d [0x%08lx]\n", copied, tmp); if (copied != sizeof(tmp)) break; @@ -281,9 +289,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) copied = sizeof(data); } else #endif - copied = - access_process_vm(child, addr + add, &data, - sizeof(data), 1); + if (addr + add >= FIXED_CODE_START + && addr + add + sizeof(data) <= FIXED_CODE_END) { + memcpy((void *)(addr + add), &data, sizeof(data)); + copied = sizeof(data); + } else + copied = access_process_vm(child, addr + add, &data, + sizeof(data), 1); pr_debug("ptrace: copied size %d\n", copied); if (copied != sizeof(data)) break; diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c new file mode 100644 index 00000000000..356078ec462 --- /dev/null +++ b/arch/blackfin/kernel/reboot.c @@ -0,0 +1,78 @@ +/* + * arch/blackfin/kernel/reboot.c - handle shutdown/reboot + * + * Copyright 2004-2007 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/interrupt.h> +#include <asm/bfin-global.h> +#include <asm/reboot.h> +#include <asm/system.h> + +#if defined(BF537_FAMILY) || defined(BF533_FAMILY) +#define SYSCR_VAL 0x0 +#elif defined(BF561_FAMILY) +#define SYSCR_VAL 0x20 +#elif defined(BF548_FAMILY) +#define SYSCR_VAL 0x10 +#endif + +/* A system soft reset makes external memory unusable + * so force this function into L1. + */ +__attribute__((l1_text)) +void bfin_reset(void) +{ + /* force BMODE and disable Core B (as needed) */ + bfin_write_SYSCR(SYSCR_VAL); + + /* we use asm ssync here because it's save and we save some L1 */ + asm("ssync;"); + + while (1) { + /* initiate system soft reset with magic 0x7 */ + bfin_write_SWRST(0x7); + asm("ssync;"); + /* clear system soft reset */ + bfin_write_SWRST(0); + asm("ssync;"); + /* issue core reset */ + asm("raise 1"); + } +} + +__attribute__((weak)) +void native_machine_restart(char *cmd) +{ +} + +void machine_restart(char *cmd) +{ + native_machine_restart(cmd); + local_irq_disable(); + bfin_reset(); +} + +__attribute__((weak)) +void native_machine_halt(void) +{ + idle_with_irq_disabled(); +} + +void machine_halt(void) +{ + native_machine_halt(); +} + +__attribute__((weak)) +void native_machine_power_off(void) +{ + idle_with_irq_disabled(); +} + +void machine_power_off(void) +{ + native_machine_power_off(); +} diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 88f221b89b3..8dcd76e87ed 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -39,10 +39,12 @@ #include <linux/cramfs_fs.h> #include <linux/romfs_fs.h> +#include <asm/cplb.h> #include <asm/cacheflush.h> #include <asm/blackfin.h> #include <asm/cplbinit.h> #include <asm/fixed_code.h> +#include <asm/early_printk.h> u16 _bfin_swrst; @@ -66,21 +68,21 @@ char __initdata command_line[COMMAND_LINE_SIZE]; void __init bf53x_cache_init(void) { -#if defined(CONFIG_BLKFIN_DCACHE) || defined(CONFIG_BLKFIN_CACHE) +#if defined(CONFIG_BFIN_DCACHE) || defined(CONFIG_BFIN_ICACHE) generate_cpl_tables(); #endif -#ifdef CONFIG_BLKFIN_CACHE +#ifdef CONFIG_BFIN_ICACHE bfin_icache_init(); printk(KERN_INFO "Instruction Cache Enabled\n"); #endif -#ifdef CONFIG_BLKFIN_DCACHE +#ifdef CONFIG_BFIN_DCACHE bfin_dcache_init(); printk(KERN_INFO "Data Cache Enabled" -# if defined CONFIG_BLKFIN_WB +# if defined CONFIG_BFIN_WB " (write-back)" -# elif defined CONFIG_BLKFIN_WT +# elif defined CONFIG_BFIN_WT " (write-through)" # endif "\n"); @@ -156,8 +158,10 @@ static __init void parse_cmdline_early(char *cmdline_p) 1; } } + } else if (!memcmp(to, "earlyprintk=", 12)) { + to += 12; + setup_early_printk(to); } - } c = *(to++); if (!c) @@ -176,22 +180,36 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; #endif + +#if defined(CONFIG_CMDLINE_BOOL) + strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); + command_line[sizeof(command_line) - 1] = 0; +#endif + + /* Keep a copy of command line */ + *cmdline_p = &command_line[0]; + memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); + boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + + /* setup memory defaults from the user config */ + physical_mem_end = 0; + _ramend = CONFIG_MEM_SIZE * 1024 * 1024; + + parse_cmdline_early(&command_line[0]); + cclk = get_cclk(); sclk = get_sclk(); -#if !defined(CONFIG_BFIN_KERNEL_CLOCK) && defined(ANOMALY_05000273) - if (cclk == sclk) +#if !defined(CONFIG_BFIN_KERNEL_CLOCK) + if (ANOMALY_05000273 && cclk == sclk) panic("ANOMALY 05000273, SCLK can not be same as CCLK"); #endif -#if defined(ANOMALY_05000266) - bfin_read_IMDMA_D0_IRQ_STATUS(); - bfin_read_IMDMA_D1_IRQ_STATUS(); -#endif - -#ifdef DEBUG_SERIAL_EARLY_INIT - bfin_console_init(); /* early console registration */ - /* this give a chance to get printk() working before crash. */ +#ifdef BF561_FAMILY + if (ANOMALY_05000266) { + bfin_read_IMDMA_D0_IRQ_STATUS(); + bfin_read_IMDMA_D1_IRQ_STATUS(); + } #endif printk(KERN_INFO "Hardware Trace "); @@ -212,22 +230,6 @@ void __init setup_arch(char **cmdline_p) flash_probe(); #endif -#if defined(CONFIG_CMDLINE_BOOL) - strncpy(&command_line[0], CONFIG_CMDLINE, sizeof(command_line)); - command_line[sizeof(command_line) - 1] = 0; -#endif - - /* Keep a copy of command line */ - *cmdline_p = &command_line[0]; - memcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); - boot_command_line[COMMAND_LINE_SIZE - 1] = '\0'; - - /* setup memory defaults from the user config */ - physical_mem_end = 0; - _ramend = CONFIG_MEM_SIZE * 1024 * 1024; - - parse_cmdline_early(&command_line[0]); - if (physical_mem_end == 0) physical_mem_end = _ramend; @@ -260,7 +262,7 @@ void __init setup_arch(char **cmdline_p) && ((unsigned long *)mtd_phys)[1] == ROMSB_WORD1) mtd_size = PAGE_ALIGN(be32_to_cpu(((unsigned long *)mtd_phys)[2])); -# if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) +# if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -289,7 +291,7 @@ void __init setup_arch(char **cmdline_p) _ebss = memory_mtd_start; /* define _ebss for compatible */ #endif /* CONFIG_MTD_UCLINUX */ -#if (defined(CONFIG_BLKFIN_CACHE) && defined(ANOMALY_05000263)) +#if (defined(CONFIG_BFIN_ICACHE) && ANOMALY_05000263) /* Due to a Hardware Anomaly we need to limit the size of usable * instruction memory to max 60MB, 56 if HUNT_FOR_ZERO is on * 05000263 - Hardware loop corrupted when taking an ICPLB exception @@ -334,13 +336,11 @@ void __init setup_arch(char **cmdline_p) CPU, bfin_revid()); printk(KERN_INFO "Blackfin Linux support by http://blackfin.uclinux.org/\n"); - printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu Mhz System Clock\n", + printk(KERN_INFO "Processor Speed: %lu MHz core clock and %lu MHz System Clock\n", cclk / 1000000, sclk / 1000000); -#if defined(ANOMALY_05000273) - if ((cclk >> 1) <= sclk) + if (ANOMALY_05000273 && (cclk >> 1) <= sclk) printk("\n\n\nANOMALY_05000273: CCLK must be >= 2*SCLK !!!\n\n\n"); -#endif printk(KERN_INFO "Board Memory: %ldMB\n", physical_mem_end >> 20); printk(KERN_INFO "Kernel Managed Memory: %ldMB\n", _ramend >> 20); @@ -535,9 +535,9 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "I-CACHE:\tOFF\n"); if ((bfin_read_DMEM_CONTROL()) & (ENDCPLB | DMC_ENABLE)) seq_printf(m, "D-CACHE:\tON" -#if defined CONFIG_BLKFIN_WB +#if defined CONFIG_BFIN_WB " (write-back)" -#elif defined CONFIG_BLKFIN_WT +#elif defined CONFIG_BFIN_WT " (write-through)" #endif "\n"); @@ -566,15 +566,15 @@ static int show_cpuinfo(struct seq_file *m, void *v) } - seq_printf(m, "I-CACHE Size:\t%dKB\n", BLKFIN_ICACHESIZE / 1024); + seq_printf(m, "I-CACHE Size:\t%dKB\n", BFIN_ICACHESIZE / 1024); seq_printf(m, "D-CACHE Size:\t%dKB\n", dcache_size); seq_printf(m, "I-CACHE Setup:\t%d Sub-banks/%d Ways, %d Lines/Way\n", - BLKFIN_ISUBBANKS, BLKFIN_IWAYS, BLKFIN_ILINES); + BFIN_ISUBBANKS, BFIN_IWAYS, BFIN_ILINES); seq_printf(m, "D-CACHE Setup:\t%d Super-banks/%d Sub-banks/%d Ways, %d Lines/Way\n", - dsup_banks, BLKFIN_DSUBBANKS, BLKFIN_DWAYS, - BLKFIN_DLINES); -#ifdef CONFIG_BLKFIN_CACHE_LOCK + dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS, + BFIN_DLINES); +#ifdef CONFIG_BFIN_ICACHE_LOCK switch (read_iloc()) { case WAY0_L: seq_printf(m, "Way0 Locked-Down\n"); diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 792a8416fe1..8823e9ade58 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -51,10 +51,9 @@ void __init trap_init(void) CSYNC(); } -asmlinkage void trap_c(struct pt_regs *fp); - int kstack_depth_to_print = 48; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON static int printk_address(unsigned long address) { struct vm_list_struct *vml; @@ -131,10 +130,22 @@ static int printk_address(unsigned long address) /* we were unable to find this address anywhere */ return printk("[<0x%p>]", (void *)address); } +#endif + +asmlinkage void double_fault_c(struct pt_regs *fp) +{ + printk(KERN_EMERG "\n" KERN_EMERG "Double Fault\n"); + dump_bfin_regs(fp, (void *)fp->retx); + panic("Double Fault - unrecoverable event\n"); + +} asmlinkage void trap_c(struct pt_regs *fp) { - int j, sig = 0; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + int j; +#endif + int sig = 0; siginfo_t info; unsigned long trapnr = fp->seqstat & SEQSTAT_EXCAUSE; @@ -391,10 +402,6 @@ asmlinkage void trap_c(struct pt_regs *fp) break; } - info.si_signo = sig; - info.si_errno = 0; - info.si_addr = (void *)fp->pc; - force_sig_info(sig, &info, current); if (sig != 0 && sig != SIGTRAP) { unsigned long stack; dump_bfin_regs(fp, (void *)fp->retx); @@ -403,6 +410,10 @@ asmlinkage void trap_c(struct pt_regs *fp) if (current->mm == NULL) panic("Kernel exception"); } + info.si_signo = sig; + info.si_errno = 0; + info.si_addr = (void *)fp->pc; + force_sig_info(sig, &info, current); /* if the address that we are about to return to is not valid, set it * to a valid address, if we have a current application or panic @@ -429,24 +440,56 @@ asmlinkage void trap_c(struct pt_regs *fp) /* Typical exception handling routines */ +#define EXPAND_LEN ((1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 256 - 1) + void dump_bfin_trace_buffer(void) { - int tflags; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON + int tflags, i = 0; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + int j, index; +#endif + trace_buffer_save(tflags); + printk(KERN_EMERG "Hardware Trace:\n"); + if (likely(bfin_read_TBUFSTAT() & TBUFCNT)) { - int i; - printk(KERN_EMERG "Hardware Trace:\n"); - for (i = 0; bfin_read_TBUFSTAT() & TBUFCNT; i++) { - printk(KERN_EMERG "%2i Target : ", i); + for (; bfin_read_TBUFSTAT() & TBUFCNT; i++) { + printk(KERN_EMERG "%4i Target : ", i); printk_address((unsigned long)bfin_read_TBUF()); - printk("\n" KERN_EMERG " Source : "); + printk("\n" KERN_EMERG " Source : "); printk_address((unsigned long)bfin_read_TBUF()); printk("\n"); } } +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_EXPAND + if (trace_buff_offset) + index = trace_buff_offset/4 - 1; + else + index = EXPAND_LEN; + + j = (1 << CONFIG_DEBUG_BFIN_HWTRACE_EXPAND_LEN) * 128; + while (j) { + printk(KERN_EMERG "%4i Target : ", i); + printk_address(software_trace_buff[index]); + index -= 1; + if (index < 0 ) + index = EXPAND_LEN; + printk("\n" KERN_EMERG " Source : "); + printk_address(software_trace_buff[index]); + index -= 1; + if (index < 0) + index = EXPAND_LEN; + printk("\n"); + j--; + i++; + } +#endif + trace_buffer_restore(tflags); +#endif } EXPORT_SYMBOL(dump_bfin_trace_buffer); @@ -510,7 +553,9 @@ void show_stack(struct task_struct *task, unsigned long *stack) void dump_stack(void) { unsigned long stack; +#ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON int tflags; +#endif trace_buffer_save(tflags); dump_bfin_trace_buffer(); show_stack(current, &stack); @@ -559,8 +604,7 @@ void dump_bfin_regs(struct pt_regs *fp, void *retaddr) unsigned short x = 0; for (; i < ((unsigned int)retaddr & 0xFFFFFFF0) + 32; i += 2) { if (!(i & 0xF)) - printk(KERN_EMERG "\n" KERN_EMERG - "0x%08x: ", i); + printk("\n" KERN_EMERG "0x%08x: ", i); if (get_user(x, (unsigned short *)i)) break; @@ -655,6 +699,42 @@ asmlinkage int sys_bfin_spinlock(int *spinlock) return ret; } +int bfin_request_exception(unsigned int exception, void (*handler)(void)) +{ + void (*curr_handler)(void); + + if (exception > 0x3F) + return -EINVAL; + + curr_handler = ex_table[exception]; + + if (curr_handler != ex_replaceable) + return -EBUSY; + + ex_table[exception] = handler; + + return 0; +} +EXPORT_SYMBOL(bfin_request_exception); + +int bfin_free_exception(unsigned int exception, void (*handler)(void)) +{ + void (*curr_handler)(void); + + if (exception > 0x3F) + return -EINVAL; + + curr_handler = ex_table[exception]; + + if (curr_handler != handler) + return -EBUSY; + + ex_table[exception] = ex_replaceable; + + return 0; +} +EXPORT_SYMBOL(bfin_free_exception); + void panic_cplb_error(int cplb_panic, struct pt_regs *fp) { switch (cplb_panic) { diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index fb53780247b..eec43674a46 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -49,7 +49,8 @@ SECTIONS TEXT_TEXT SCHED_TEXT LOCK_TEXT - *(.text.lock) + KPROBES_TEXT + *(.text.*) *(.fixup) . = ALIGN(16); @@ -61,7 +62,7 @@ SECTIONS __etext = .; } - RODATA + RO_DATA(PAGE_SIZE) .data : { @@ -72,50 +73,63 @@ SECTIONS __sdata = .; . = ALIGN(THREAD_SIZE); *(.data.init_task) - DATA_DATA - CONSTRUCTORS . = ALIGN(32); *(.data.cacheline_aligned) + DATA_DATA + *(.data.*) + CONSTRUCTORS + . = ALIGN(THREAD_SIZE); __edata = .; } ___init_begin = .; - .init : + + .init.text : { . = ALIGN(PAGE_SIZE); __sinittext = .; *(.init.text) __einittext = .; + } + .init.data : + { + . = ALIGN(16); *(.init.data) + } + .init.setup : + { . = ALIGN(16); ___setup_start = .; *(.init.setup) ___setup_end = .; - ___start___param = .; - *(__param) - ___stop___param = .; + } + .initcall.init : + { ___initcall_start = .; INITCALLS ___initcall_end = .; + } + .con_initcall.init : + { ___con_initcall_start = .; *(.con_initcall.init) ___con_initcall_end = .; - ___security_initcall_start = .; - *(.security_initcall.init) - ___security_initcall_end = .; + } + SECURITY_INIT + .init.ramfs : + { . = ALIGN(4); ___initramfs_start = .; *(.init.ramfs) ___initramfs_end = .; - . = ALIGN(4); } __l1_lma_start = .; - .text_l1 L1_CODE_START : AT(LOADADDR(.init) + SIZEOF(.init)) + .text_l1 L1_CODE_START : AT(LOADADDR(.init.ramfs) + SIZEOF(.init.ramfs)) { . = ALIGN(4); __stext_l1 = .; @@ -164,13 +178,19 @@ SECTIONS { . = ALIGN(4); ___bss_start = .; - *(.bss) + *(.bss .bss.*) *(COMMON) . = ALIGN(4); ___bss_stop = .; __end = .; } + STABS_DEBUG + + DWARF_DEBUG + + NOTES + /DISCARD/ : { *(.exit.text) |