From 66a4909a3d4d684f7a102f4d4d2ba8ae8c66d786 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 29 Apr 2010 00:31:36 -0400 Subject: Blackfin: clean up trace buffer handling when crashing Avoid banging on the trace MMRs when debugging is disabled, avoid calling the funcs multiple times in a row, disable the trace buffer earlier in the exception handler to avoid eating more user entries, and dump the buffer before calling the kgdb hook. This way we maximize useful debugging info up front rather than needing external tools (like gdb/serial/etc...). Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/cpu.h | 1 + arch/blackfin/cpu/traps.c | 76 ++++++++++++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 28 deletions(-) (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/cpu.h b/arch/blackfin/cpu/cpu.h index 0a13c285e0..c8bec115a1 100644 --- a/arch/blackfin/cpu/cpu.h +++ b/arch/blackfin/cpu/cpu.h @@ -29,6 +29,7 @@ void board_reset(void) __attribute__((__weak__)); void bfin_reset_or_hang(void) __attribute__((__noreturn__)); +void bfin_dump(struct pt_regs *reg); void bfin_panic(struct pt_regs *reg); void dump(struct pt_regs *regs); diff --git a/arch/blackfin/cpu/traps.c b/arch/blackfin/cpu/traps.c index caaea94106..09388aa3d5 100644 --- a/arch/blackfin/cpu/traps.c +++ b/arch/blackfin/cpu/traps.c @@ -29,14 +29,26 @@ #include #include "cpu.h" +#ifdef CONFIG_DEBUG_DUMP +# define ENABLE_DUMP 1 +#else +# define ENABLE_DUMP 0 +#endif + #define trace_buffer_save(x) \ do { \ + if (!ENABLE_DUMP) \ + break; \ (x) = bfin_read_TBUFCTL(); \ bfin_write_TBUFCTL((x) & ~TBUFEN); \ } while (0) #define trace_buffer_restore(x) \ - bfin_write_TBUFCTL((x)) + do { \ + if (!ENABLE_DUMP) \ + break; \ + bfin_write_TBUFCTL((x)); \ + } while (0); /* The purpose of this map is to provide a mapping of address<->cplb settings * rather than an exact map of what is actually addressable on the part. This @@ -82,8 +94,16 @@ int trap_c(struct pt_regs *regs, uint32_t level) { uint32_t ret = 0; uint32_t trapnr = (regs->seqstat & EXCAUSE); + unsigned long tflags; bool data = false; + /* + * Keep the trace buffer so that a miss here points people + * to the right place (their code). Crashes here rarely + * happen. If they do, only the Blackfin maintainer cares. + */ + trace_buffer_save(tflags); + switch (trapnr) { /* 0x26 - Data CPLB Miss */ case VEC_CPLB_M: @@ -97,7 +117,7 @@ int trap_c(struct pt_regs *regs, uint32_t level) */ if (last_cplb_fault_retx != regs->retx) { last_cplb_fault_retx = regs->retx; - return ret; + break; } } @@ -110,7 +130,6 @@ int trap_c(struct pt_regs *regs, uint32_t level) uint32_t new_cplb_addr = 0, new_cplb_data = 0; static size_t last_evicted; size_t i; - unsigned long tflags; #ifdef CONFIG_EXCEPTION_DEFER /* This should never happen */ @@ -118,13 +137,6 @@ int trap_c(struct pt_regs *regs, uint32_t level) bfin_panic(regs); #endif - /* - * Keep the trace buffer so that a miss here points people - * to the right place (their code). Crashes here rarely - * happen. If they do, only the Blackfin maintainer cares. - */ - trace_buffer_save(tflags); - new_cplb_addr = (data ? bfin_read_DCPLB_FAULT_ADDR() : bfin_read_ICPLB_FAULT_ADDR()) & ~(4 * 1024 * 1024 - 1); for (i = 0; i < ARRAY_SIZE(bfin_memory_map); ++i) { @@ -180,7 +192,6 @@ int trap_c(struct pt_regs *regs, uint32_t level) for (i = 0; i < 16; ++i) debug("%2i 0x%p 0x%08X\n", i, *CPLB_ADDR++, *CPLB_DATA++); - trace_buffer_restore(tflags); break; } #ifdef CONFIG_CMD_KGDB @@ -208,23 +219,21 @@ int trap_c(struct pt_regs *regs, uint32_t level) #ifdef CONFIG_CMD_KGDB if (level == 3) { /* We need to handle this at EVT5, so try again */ + bfin_dump(regs); ret = 1; break; } if (debugger_exception_handler && (*debugger_exception_handler)(regs)) - return 0; + break; #endif bfin_panic(regs); } + + trace_buffer_restore(tflags); + return ret; } -#ifdef CONFIG_DEBUG_DUMP -# define ENABLE_DUMP 1 -#else -# define ENABLE_DUMP 0 -#endif - #ifndef CONFIG_KALLSYMS const char *symbol_lookup(unsigned long addr, unsigned long *caddr) { @@ -364,17 +373,14 @@ void dump(struct pt_regs *fp) printf("\n"); } -void dump_bfin_trace_buffer(void) +static void _dump_bfin_trace_buffer(void) { char buf[150]; - unsigned long tflags; int i = 0; if (!ENABLE_DUMP) return; - trace_buffer_save(tflags); - printf("Hardware Trace:\n"); if (bfin_read_TBUFSTAT() & TBUFCNT) { @@ -385,16 +391,21 @@ void dump_bfin_trace_buffer(void) printf(" Source : %s\n", buf); } } +} +void dump_bfin_trace_buffer(void) +{ + unsigned long tflags; + trace_buffer_save(tflags); + _dump_bfin_trace_buffer(); trace_buffer_restore(tflags); } -void bfin_panic(struct pt_regs *regs) +void bfin_dump(struct pt_regs *regs) { - if (ENABLE_DUMP) { - unsigned long tflags; - trace_buffer_save(tflags); - } + unsigned long tflags; + + trace_buffer_save(tflags); puts( "\n" @@ -404,7 +415,16 @@ void bfin_panic(struct pt_regs *regs) "\n" ); dump(regs); - dump_bfin_trace_buffer(); + _dump_bfin_trace_buffer(); puts("\n"); + + trace_buffer_restore(tflags); +} + +void bfin_panic(struct pt_regs *regs) +{ + unsigned long tflags; + trace_buffer_save(tflags); + bfin_dump(regs); bfin_reset_or_hang(); } -- cgit From a5384ae49a52e2d4744aed20d729ccf20e7a907a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 29 Apr 2010 01:34:57 -0400 Subject: Blackfin: implement bootcount support The default storage location for bootcount is EVT0. This version uses one 32bit value and combines the magic/count value in the upper/lower 16bits. If there is demand for more, should be easy to do. Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/Makefile | 1 + arch/blackfin/cpu/bootcount.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 arch/blackfin/cpu/bootcount.c (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/Makefile b/arch/blackfin/cpu/Makefile index 211b8d5450..50c1eeab9d 100644 --- a/arch/blackfin/cpu/Makefile +++ b/arch/blackfin/cpu/Makefile @@ -17,6 +17,7 @@ EXTRA := CEXTRA := initcode.o SEXTRA := start.o SOBJS := interrupt.o cache.o +COBJS-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount.o COBJS-y += cpu.o COBJS-y += interrupts.o COBJS-$(CONFIG_JTAG_CONSOLE) += jtag-console.o diff --git a/arch/blackfin/cpu/bootcount.c b/arch/blackfin/cpu/bootcount.c new file mode 100644 index 0000000000..6cf6dd58b6 --- /dev/null +++ b/arch/blackfin/cpu/bootcount.c @@ -0,0 +1,34 @@ +/* + * functions for handling bootcount support + * + * Copyright (c) 2010 Analog Devices Inc. + * + * Licensed under the 2-clause BSD. + */ + +/* This version uses one 32bit storage and combines the magic/count */ + +#include + +/* We abuse the EVT0 MMR for bootcount storage by default */ +#ifndef CONFIG_SYS_BOOTCOUNT_ADDR +# define CONFIG_SYS_BOOTCOUNT_ADDR EVT0 +#endif + +#define MAGIC_MASK 0xffff0000 +#define COUNT_MASK 0x0000ffff + +void bootcount_store(ulong cnt) +{ + ulong magic = (BOOTCOUNT_MAGIC & MAGIC_MASK) | (cnt & COUNT_MASK); + bfin_write32(CONFIG_SYS_BOOTCOUNT_ADDR, magic); +} + +ulong bootcount_load(void) +{ + ulong magic = bfin_read32(CONFIG_SYS_BOOTCOUNT_ADDR); + if ((magic & MAGIC_MASK) == (BOOTCOUNT_MAGIC & MAGIC_MASK)) + return magic & COUNT_MASK; + else + return 0; +} -- cgit From b30453ace4eb930ab224012bd2367fa3d1337ced Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Thu, 29 Apr 2010 02:49:41 -0400 Subject: Blackfin: expand EVT1 usage documentation a bit more Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/initcode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c index 5f80ad615e..9453d5dc4d 100644 --- a/arch/blackfin/cpu/initcode.c +++ b/arch/blackfin/cpu/initcode.c @@ -675,7 +675,12 @@ void initcode(ADI_BOOT_DATA *bs) #ifdef CONFIG_BFIN_BOOTROM_USES_EVT1 serial_putc('I'); - /* tell the bootrom where our entry point is */ + /* Tell the bootrom where our entry point is so that it knows + * where to jump to when finishing processing the LDR. This + * allows us to avoid small jump blocks in the LDR, and also + * works around anomaly 05000389 (init address in external + * memory causes bootrom to trigger external addressing IVHW). + */ if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS) bfin_write_EVT1(CONFIG_SYS_MONITOR_BASE); #endif -- cgit From ce53fc660114a2c23e6e8adbc197008b36ca444d Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 5 May 2010 02:07:44 -0400 Subject: Blackfin: set up simple NMI handlers for anomaly 05000219 Older on-chip Blackfin bootroms do not create a dummy NMI handler, so set up one ourselves when anomaly 05000219 applies. Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/cpu.c | 4 +++- arch/blackfin/cpu/cpu.h | 1 + arch/blackfin/cpu/initcode.c | 25 +++++++++++++++++++++++++ arch/blackfin/cpu/interrupt.S | 5 +++++ 4 files changed, 34 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/cpu.c b/arch/blackfin/cpu/cpu.c index 2c8fd86b86..18dbdf7abe 100644 --- a/arch/blackfin/cpu/cpu.c +++ b/arch/blackfin/cpu/cpu.c @@ -91,7 +91,9 @@ int irq_init(void) #else bfin_write_SIC_IMASK(0); #endif - bfin_write_EVT2(evt_default); /* NMI */ + /* Set up a dummy NMI handler if needed. */ + if (CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_BYPASS || ANOMALY_05000219) + bfin_write_EVT2(evt_nmi); /* NMI */ bfin_write_EVT5(evt_default); /* hardware error */ bfin_write_EVT6(evt_default); /* core timer */ bfin_write_EVT7(evt_default); diff --git a/arch/blackfin/cpu/cpu.h b/arch/blackfin/cpu/cpu.h index c8bec115a1..ba85e0b9a5 100644 --- a/arch/blackfin/cpu/cpu.h +++ b/arch/blackfin/cpu/cpu.h @@ -34,6 +34,7 @@ void bfin_panic(struct pt_regs *reg); void dump(struct pt_regs *regs); asmlinkage void trap(void); +asmlinkage void evt_nmi(void); asmlinkage void evt_default(void); #endif diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c index 9453d5dc4d..007f5ce775 100644 --- a/arch/blackfin/cpu/initcode.c +++ b/arch/blackfin/cpu/initcode.c @@ -101,6 +101,28 @@ static inline void serial_putc(char c) continue; } +__attribute__((always_inline)) static inline void +program_nmi_handler(void) +{ + u32 tmp1, tmp2; + + /* Older bootroms don't create a dummy NMI handler, + * so make one ourselves ASAP in case it fires. + */ + if (CONFIG_BFIN_BOOT_MODE != BFIN_BOOT_BYPASS && !ANOMALY_05000219) + return; + + asm volatile ( + "%0 = RETS;" /* Save current RETS */ + "CALL 1f;" /* Figure out current PC */ + "RTN;" /* The simple NMI handler */ + "1:" + "%1 = RETS;" /* Load addr of NMI handler */ + "RETS = %0;" /* Restore RETS */ + "[%2] = %1;" /* Write NMI handler */ + : "=r"(tmp1), "=r"(tmp2) : "ab"(EVT2) + ); +} /* Max SCLK can be 133MHz ... dividing that by (2*4) gives * us a freq of 16MHz for SPI which should generally be @@ -640,6 +662,9 @@ void initcode(ADI_BOOT_DATA *bs) { ADI_BOOT_DATA bootstruct_scratch; + /* Setup NMI handler before anything else */ + program_nmi_handler(); + serial_init(); serial_putc('A'); diff --git a/arch/blackfin/cpu/interrupt.S b/arch/blackfin/cpu/interrupt.S index 69bba3f5ee..0e5e59e15d 100644 --- a/arch/blackfin/cpu/interrupt.S +++ b/arch/blackfin/cpu/interrupt.S @@ -150,3 +150,8 @@ ENTRY(_evt_default) RESTORE_ALL_SYS rti; ENDPROC(_evt_default) + +/* NMI handler */ +ENTRY(_evt_nmi) + rtn; +ENDPROC(_evt_nmi) -- cgit From 4638b21f2ebc3781def51e82fb4e425a468f2e49 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 2 Jun 2010 04:17:26 -0400 Subject: Blackfin: import gpio/portmux layer from Linux The current pinmux handling has spread throughout Blackfin drivers and board code and is getting hideous to maintain. So import the gpio and portmux layer from the Blackfin Linux code. This should spur a serious of cleanups across the Blackfin tree. Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/Makefile | 1 + arch/blackfin/cpu/gpio.c | 854 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 855 insertions(+) create mode 100644 arch/blackfin/cpu/gpio.c (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/Makefile b/arch/blackfin/cpu/Makefile index 50c1eeab9d..91797c798f 100644 --- a/arch/blackfin/cpu/Makefile +++ b/arch/blackfin/cpu/Makefile @@ -19,6 +19,7 @@ SEXTRA := start.o SOBJS := interrupt.o cache.o COBJS-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount.o COBJS-y += cpu.o +COBJS-y += gpio.o COBJS-y += interrupts.o COBJS-$(CONFIG_JTAG_CONSOLE) += jtag-console.o COBJS-y += os_log.o diff --git a/arch/blackfin/cpu/gpio.c b/arch/blackfin/cpu/gpio.c new file mode 100644 index 0000000000..488ca11bb0 --- /dev/null +++ b/arch/blackfin/cpu/gpio.c @@ -0,0 +1,854 @@ +/* + * GPIO Abstraction Layer + * + * Copyright 2006-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later + */ + +#include +#include +#include +#include + +#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 + +static struct gpio_port_t * const gpio_array[] = { +#if defined(BF533_FAMILY) + (struct gpio_port_t *) FIO_FLAG_D, +#elif defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) \ + || defined(BF538_FAMILY) + (struct gpio_port_t *) PORTFIO, +# if !defined(BF538_FAMILY) + (struct gpio_port_t *) PORTGIO, + (struct gpio_port_t *) PORTHIO, +# endif +#elif defined(BF561_FAMILY) + (struct gpio_port_t *) FIO0_FLAG_D, + (struct gpio_port_t *) FIO1_FLAG_D, + (struct gpio_port_t *) FIO2_FLAG_D, +#elif defined(CONFIG_BF54x) + (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, +#else +# error no gpio arrays defined +#endif +}; + +#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) +static unsigned short * const port_fer[] = { + (unsigned short *) PORTF_FER, + (unsigned short *) PORTG_FER, + (unsigned short *) PORTH_FER, +}; + +# if !defined(BF537_FAMILY) +static unsigned short * const port_mux[] = { + (unsigned short *) PORTF_MUX, + (unsigned short *) PORTG_MUX, + (unsigned short *) PORTH_MUX, +}; + +static const +u8 pmux_offset[][16] = { +# if defined(CONFIG_BF52x) + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 8, 8, 10, 10 }, /* PORTF */ + { 0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 8, 10, 10, 10, 12, 12 }, /* PORTG */ + { 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }, /* PORTH */ +# elif defined(CONFIG_BF51x) + { 0, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6, 8, 8, 8, 8, 10 }, /* PORTF */ + { 0, 0, 0, 2, 4, 6, 6, 6, 8, 10, 10, 12, 14, 14, 14, 14 }, /* PORTG */ + { 0, 0, 0, 0, 2, 2, 4, 6, 10, 10, 10, 10, 10, 10, 10, 10 }, /* PORTH */ +# endif +}; +# endif + +#elif defined(BF538_FAMILY) +static unsigned short * const port_fer[] = { + (unsigned short *) PORTCIO_FER, + (unsigned short *) PORTDIO_FER, + (unsigned short *) PORTEIO_FER, +}; +#endif + +#ifdef CONFIG_BFIN_GPIO_TRACK +#define RESOURCE_LABEL_SIZE 16 + +static struct str_ident { + char name[RESOURCE_LABEL_SIZE]; +} str_ident[MAX_RESOURCES]; + +static void gpio_error(unsigned gpio) +{ + printf("bfin-gpio: GPIO %d wasn't requested!\n", gpio); +} + +static void set_label(unsigned short ident, const char *label) +{ + if (label) { + strncpy(str_ident[ident].name, label, + RESOURCE_LABEL_SIZE); + str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; + } +} + +static char *get_label(unsigned short ident) +{ + return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); +} + +static int cmp_label(unsigned short ident, const char *label) +{ + if (label == NULL) + printf("bfin-gpio: please provide none-null label\n"); + + if (label) + return strcmp(str_ident[ident].name, label); + else + return -EINVAL; +} + +#define map_entry(m, i) reserved_##m##_map[gpio_bank(i)] +#define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i)) +#define reserve(m, i) (map_entry(m, i) |= gpio_bit(i)) +#define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i)) +#define DECLARE_RESERVED_MAP(m, c) static unsigned short reserved_##m##_map[c] +#else +#define is_reserved(m, i, e) (!(e)) +#define reserve(m, i) +#define unreserve(m, i) +#define DECLARE_RESERVED_MAP(m, c) +#define gpio_error(gpio) +#define set_label(...) +#define get_label(...) "" +#define cmp_label(...) 1 +#endif + +DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM); +DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES)); + +inline int check_gpio(unsigned gpio) +{ +#if defined(CONFIG_BF54x) + if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 + || gpio == GPIO_PH14 || gpio == GPIO_PH15 + || gpio == GPIO_PJ14 || gpio == GPIO_PJ15) + return -EINVAL; +#endif + if (gpio >= MAX_BLACKFIN_GPIOS) + return -EINVAL; + return 0; +} + +static void port_setup(unsigned gpio, unsigned short usage) +{ +#if defined(BF538_FAMILY) + /* + * BF538/9 Port C,D and E are special. + * Inverted PORT_FER polarity on CDE and no PORF_FER on F + * Regular PORT F GPIOs are handled here, CDE are exclusively + * managed by GPIOLIB + */ + + if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES) + return; + + gpio -= MAX_BLACKFIN_GPIOS; + + if (usage == GPIO_USAGE) + *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); + else + *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); + SSYNC(); + return; +#endif + + if (check_gpio(gpio)) + return; + +#if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) + if (usage == GPIO_USAGE) + *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); + else + *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); + SSYNC(); +#elif defined(CONFIG_BF54x) + 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(); +#endif +} + +#ifdef BF537_FAMILY +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) +{ + u16 y, offset, muxreg; + u16 function = P_FUNCT2MUX(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].offset; + muxreg = bfin_read_PORT_MUX(); + + if (offset != 1) + muxreg &= ~(1 << offset); + else + muxreg &= ~(3 << 1); + + muxreg |= (function << offset); + bfin_write_PORT_MUX(muxreg); + } + } +} +#elif defined(CONFIG_BF54x) +inline void portmux_setup(unsigned short per) +{ + u32 pmux; + u16 ident = P_IDENT(per); + u16 function = P_FUNCT2MUX(per); + + pmux = gpio_array[gpio_bank(ident)]->port_mux; + + pmux &= ~(0x3 << (2 * gpio_sub_n(ident))); + pmux |= (function & 0x3) << (2 * gpio_sub_n(ident)); + + gpio_array[gpio_bank(ident)]->port_mux = pmux; +} + +inline u16 get_portmux(unsigned short per) +{ + u32 pmux; + u16 ident = P_IDENT(per); + + pmux = gpio_array[gpio_bank(ident)]->port_mux; + + return (pmux >> (2 * gpio_sub_n(ident)) & 0x3); +} +#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) +inline void portmux_setup(unsigned short per) +{ + u16 pmux, ident = P_IDENT(per), function = P_FUNCT2MUX(per); + u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; + + pmux = *port_mux[gpio_bank(ident)]; + pmux &= ~(3 << offset); + pmux |= (function & 3) << offset; + *port_mux[gpio_bank(ident)] = pmux; + SSYNC(); +} +#else +# define portmux_setup(...) do { } while (0) +#endif + +#ifndef CONFIG_BF54x +/*********************************************************** +* +* FUNCTIONS: Blackfin General Purpose Ports Access Functions +* +* INPUTS/OUTPUTS: +* gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS +* +* +* DESCRIPTION: These functions abstract direct register access +* to Blackfin processor General Purpose +* Ports Regsiters +* +* CAUTION: These functions do not belong to the GPIO Driver API +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ + +/* Set a specific bit */ + +#define SET_GPIO(name) \ +void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + local_irq_save(flags); \ + if (arg) \ + gpio_array[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ + else \ + gpio_array[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ +} + +SET_GPIO(dir) /* set_gpio_dir() */ +SET_GPIO(inen) /* set_gpio_inen() */ +SET_GPIO(polar) /* set_gpio_polar() */ +SET_GPIO(edge) /* set_gpio_edge() */ +SET_GPIO(both) /* set_gpio_both() */ + + +#define SET_GPIO_SC(name) \ +void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + if (ANOMALY_05000311 || ANOMALY_05000323) \ + local_irq_save(flags); \ + if (arg) \ + gpio_array[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ + else \ + gpio_array[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ + if (ANOMALY_05000311 || ANOMALY_05000323) { \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + } \ +} + +SET_GPIO_SC(maska) +SET_GPIO_SC(maskb) +SET_GPIO_SC(data) + +void set_gpio_toggle(unsigned gpio) +{ + unsigned long flags; + if (ANOMALY_05000311 || ANOMALY_05000323) + local_irq_save(flags); + gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio); + if (ANOMALY_05000311 || ANOMALY_05000323) { + AWA_DUMMY_READ(toggle); + local_irq_restore(flags); + } +} + +/* Set current PORT date (16-bit word) */ + +#define SET_GPIO_P(name) \ +void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \ +{ \ + unsigned long flags; \ + if (ANOMALY_05000311 || ANOMALY_05000323) \ + local_irq_save(flags); \ + gpio_array[gpio_bank(gpio)]->name = arg; \ + if (ANOMALY_05000311 || ANOMALY_05000323) { \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + } \ +} + +SET_GPIO_P(data) +SET_GPIO_P(dir) +SET_GPIO_P(inen) +SET_GPIO_P(polar) +SET_GPIO_P(edge) +SET_GPIO_P(both) +SET_GPIO_P(maska) +SET_GPIO_P(maskb) + +/* Get a specific bit */ +#define GET_GPIO(name) \ +unsigned short get_gpio_ ## name(unsigned gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + if (ANOMALY_05000311 || ANOMALY_05000323) \ + local_irq_save(flags); \ + ret = 0x01 & (gpio_array[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ + if (ANOMALY_05000311 || ANOMALY_05000323) { \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + } \ + return ret; \ +} + +GET_GPIO(data) +GET_GPIO(dir) +GET_GPIO(inen) +GET_GPIO(polar) +GET_GPIO(edge) +GET_GPIO(both) +GET_GPIO(maska) +GET_GPIO(maskb) + +/* Get current PORT date (16-bit word) */ + +#define GET_GPIO_P(name) \ +unsigned short get_gpiop_ ## name(unsigned gpio) \ +{ \ + unsigned long flags; \ + unsigned short ret; \ + if (ANOMALY_05000311 || ANOMALY_05000323) \ + local_irq_save(flags); \ + ret = (gpio_array[gpio_bank(gpio)]->name); \ + if (ANOMALY_05000311 || ANOMALY_05000323) { \ + AWA_DUMMY_READ(name); \ + local_irq_restore(flags); \ + } \ + return ret; \ +} + +GET_GPIO_P(data) +GET_GPIO_P(dir) +GET_GPIO_P(inen) +GET_GPIO_P(polar) +GET_GPIO_P(edge) +GET_GPIO_P(both) +GET_GPIO_P(maska) +GET_GPIO_P(maskb) + +#else /* CONFIG_BF54x */ + +unsigned short get_gpio_dir(unsigned gpio) +{ + return (0x01 & (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio))); +} + +#endif /* CONFIG_BF54x */ + +/*********************************************************** +* +* 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 : +**************************************************************/ + +int peripheral_request(unsigned short per, const char *label) +{ + 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; + + BUG_ON(ident >= MAX_RESOURCES); + + /* If a pin can be muxed as either GPIO or peripheral, make + * sure it is not already a GPIO pin when we request it. + */ + if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) { + printf("%s: Peripheral %d is already reserved as GPIO by %s !\n", + __func__, ident, get_label(ident)); + return -EBUSY; + } + + if (unlikely(is_reserved(peri, ident, 1))) { + + /* + * Pin functions like AMC address strobes my + * be requested and used by several drivers + */ + +#ifdef CONFIG_BF54x + if (!((per & P_MAYSHARE) && get_portmux(per) == P_FUNCT2MUX(per))) { +#else + if (!(per & P_MAYSHARE)) { +#endif + /* + * Allow that the identical pin function can + * be requested from the same driver twice + */ + + if (cmp_label(ident, label) == 0) + goto anyway; + + printf("%s: Peripheral %d function %d is already reserved by %s !\n", + __func__, ident, P_FUNCT2MUX(per), get_label(ident)); + return -EBUSY; + } + } + + anyway: + reserve(peri, ident); + + portmux_setup(per); + port_setup(ident, PERIPHERAL_USAGE); + + set_label(ident, label); + + return 0; +} + +int peripheral_request_list(const unsigned short per[], const char *label) +{ + u16 cnt; + int ret; + + for (cnt = 0; per[cnt] != 0; cnt++) { + + ret = peripheral_request(per[cnt], label); + + if (ret < 0) { + for ( ; cnt > 0; cnt--) + peripheral_free(per[cnt - 1]); + + return ret; + } + } + + return 0; +} + +void peripheral_free(unsigned short per) +{ + unsigned short ident = P_IDENT(per); + + if (per & P_DONTCARE) + return; + + if (!(per & P_DEFINED)) + return; + + if (unlikely(!is_reserved(peri, ident, 0))) + return; + + if (!(per & P_MAYSHARE)) + port_setup(ident, GPIO_USAGE); + + unreserve(peri, ident); + + set_label(ident, "free"); +} + +void peripheral_free_list(const unsigned short per[]) +{ + u16 cnt; + for (cnt = 0; per[cnt] != 0; cnt++) + peripheral_free(per[cnt]); +} + +/*********************************************************** +* +* FUNCTIONS: Blackfin GPIO Driver +* +* INPUTS/OUTPUTS: +* gpio PIO Number between 0 and MAX_BLACKFIN_GPIOS +* label String +* +* DESCRIPTION: Blackfin GPIO Driver API +* +* CAUTION: +************************************************************* +* MODIFICATION HISTORY : +**************************************************************/ + +int bfin_gpio_request(unsigned gpio, const char *label) +{ + if (check_gpio(gpio) < 0) + return -EINVAL; + + /* + * Allow that the identical GPIO can + * be requested from the same driver twice + * Do nothing and return - + */ + + if (cmp_label(gpio, label) == 0) + return 0; + + if (unlikely(is_reserved(gpio, gpio, 1))) { + printf("bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); + return -EBUSY; + } + if (unlikely(is_reserved(peri, gpio, 1))) { + printf("bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + return -EBUSY; + } +#ifndef CONFIG_BF54x + else { /* Reset POLAR setting when acquiring a gpio for the first time */ + set_gpio_polar(gpio, 0); + } +#endif + + reserve(gpio, gpio); + set_label(gpio, label); + + port_setup(gpio, GPIO_USAGE); + + return 0; +} + +void bfin_gpio_free(unsigned gpio) +{ + if (check_gpio(gpio) < 0) + return; + + if (unlikely(!is_reserved(gpio, gpio, 0))) { + gpio_error(gpio); + return; + } + + unreserve(gpio, gpio); + + set_label(gpio, "free"); +} + +#ifdef BFIN_SPECIAL_GPIO_BANKS +DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES)); + +int bfin_special_gpio_request(unsigned gpio, const char *label) +{ + /* + * Allow that the identical GPIO can + * be requested from the same driver twice + * Do nothing and return - + */ + + if (cmp_label(gpio, label) == 0) + return 0; + + if (unlikely(is_reserved(special_gpio, gpio, 1))) { + printf("bfin-gpio: GPIO %d is already reserved by %s !\n", + gpio, get_label(gpio)); + return -EBUSY; + } + if (unlikely(is_reserved(peri, gpio, 1))) { + printf("bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", + gpio, get_label(gpio)); + + return -EBUSY; + } + + reserve(special_gpio, gpio); + reserve(peri, gpio); + + set_label(gpio, label); + port_setup(gpio, GPIO_USAGE); + + return 0; +} + +void bfin_special_gpio_free(unsigned gpio) +{ + if (unlikely(!is_reserved(special_gpio, gpio, 0))) { + gpio_error(gpio); + return; + } + + reserve(special_gpio, gpio); + reserve(peri, gpio); + set_label(gpio, "free"); +} +#endif + +static inline void __bfin_gpio_direction_input(unsigned gpio) +{ +#ifdef CONFIG_BF54x + gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio); +#else + gpio_array[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); +#endif + gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio); +} + +int bfin_gpio_direction_input(unsigned gpio) +{ + unsigned long flags; + + if (!is_reserved(gpio, gpio, 0)) { + gpio_error(gpio); + return -EINVAL; + } + + local_irq_save(flags); + __bfin_gpio_direction_input(gpio); + AWA_DUMMY_READ(inen); + local_irq_restore(flags); + + return 0; +} + +void bfin_gpio_toggle_value(unsigned gpio) +{ +#ifdef CONFIG_BF54x + gpio_set_value(gpio, !gpio_get_value(gpio)); +#else + gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio); +#endif +} + +void bfin_gpio_set_value(unsigned gpio, int arg) +{ + if (arg) + gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); + else + gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); +} + +int bfin_gpio_direction_output(unsigned gpio, int value) +{ + unsigned long flags; + + if (!is_reserved(gpio, gpio, 0)) { + gpio_error(gpio); + return -EINVAL; + } + + local_irq_save(flags); + + gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); + gpio_set_value(gpio, value); +#ifdef CONFIG_BF54x + gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio); +#else + gpio_array[gpio_bank(gpio)]->dir |= gpio_bit(gpio); +#endif + + AWA_DUMMY_READ(dir); + local_irq_restore(flags); + + return 0; +} + +int bfin_gpio_get_value(unsigned gpio) +{ +#ifdef CONFIG_BF54x + return (1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio))); +#else + unsigned long flags; + + if (unlikely(get_gpio_edge(gpio))) { + int ret; + local_irq_save(flags); + set_gpio_edge(gpio, 0); + ret = get_gpio_data(gpio); + set_gpio_edge(gpio, 1); + local_irq_restore(flags); + return ret; + } else + return get_gpio_data(gpio); +#endif +} + +/* 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_reset_boot_spi_cs(unsigned short pin) +{ + unsigned short gpio = P_IDENT(pin); + port_setup(gpio, GPIO_USAGE); + gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); + AWA_DUMMY_READ(data_set); + udelay(1); +} + +#ifdef CONFIG_BFIN_GPIO_TRACK +void bfin_gpio_labels(void) +{ + int c, gpio; + + for (c = 0; c < MAX_RESOURCES; c++) { + gpio = is_reserved(gpio, c, 1); + if (!check_gpio(c) && gpio) + printf("GPIO_%d:\t%s\tGPIO %s\n", c, + get_label(c), + get_gpio_dir(c) ? "OUTPUT" : "INPUT"); + else if (is_reserved(peri, c, 1)) + printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c)); + else + continue; + } +} +#endif -- cgit From c5530555f82f6fbaf51656e9ba10e295d3c5f195 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 2 Jun 2010 04:34:49 -0400 Subject: Blackfin: unify custom gpio commands Now that we have a unified gpio layer, the misc partial gpio commands can be unified and made complete (support all possible gpios). Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/Makefile | 1 + arch/blackfin/cpu/cmd_gpio.c | 120 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 arch/blackfin/cpu/cmd_gpio.c (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/Makefile b/arch/blackfin/cpu/Makefile index 91797c798f..b7f991dea0 100644 --- a/arch/blackfin/cpu/Makefile +++ b/arch/blackfin/cpu/Makefile @@ -18,6 +18,7 @@ CEXTRA := initcode.o SEXTRA := start.o SOBJS := interrupt.o cache.o COBJS-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount.o +COBJS-$(CONFIG_CMD_GPIO) += cmd_gpio.o COBJS-y += cpu.o COBJS-y += gpio.o COBJS-y += interrupts.o diff --git a/arch/blackfin/cpu/cmd_gpio.c b/arch/blackfin/cpu/cmd_gpio.c new file mode 100644 index 0000000000..9e505b6617 --- /dev/null +++ b/arch/blackfin/cpu/cmd_gpio.c @@ -0,0 +1,120 @@ +/* + * Control GPIO pins on the fly + * + * Copyright (c) 2008-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#include +#include + +#include +#include + +enum { + GPIO_INPUT, + GPIO_SET, + GPIO_CLEAR, + GPIO_TOGGLE, +}; + +int do_gpio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + if (argc == 2 && !strcmp(argv[1], "status")) { + bfin_gpio_labels(); + return 0; + } + + if (argc != 3) { + show_usage: + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + /* parse the behavior */ + ulong sub_cmd; + switch (argv[1][0]) { + case 'i': sub_cmd = GPIO_INPUT; break; + case 's': sub_cmd = GPIO_SET; break; + case 'c': sub_cmd = GPIO_CLEAR; break; + case 't': sub_cmd = GPIO_TOGGLE; break; + default: goto show_usage; + } + + /* parse the pin with format: [p][port]<#> */ + const char *str_pin = argv[2]; + + /* grab the [p] portion */ + ulong port_base; + if (*str_pin == 'p') ++str_pin; + switch (*str_pin) { +#ifdef GPIO_PA0 + case 'a': port_base = GPIO_PA0; break; +#endif +#ifdef GPIO_PB0 + case 'b': port_base = GPIO_PB0; break; +#endif +#ifdef GPIO_PC0 + case 'c': port_base = GPIO_PC0; break; +#endif +#ifdef GPIO_PD0 + case 'd': port_base = GPIO_PD0; break; +#endif +#ifdef GPIO_PE0 + case 'e': port_base = GPIO_PE0; break; +#endif +#ifdef GPIO_PF0 + case 'f': port_base = GPIO_PF0; break; +#endif +#ifdef GPIO_PG0 + case 'g': port_base = GPIO_PG0; break; +#endif +#ifdef GPIO_PH0 + case 'h': port_base = GPIO_PH0; break; +#endif +#ifdef GPIO_PI0 + case 'i': port_base = GPIO_PI0; break; +#endif +#ifdef GPIO_PJ + case 'j': port_base = GPIO_PJ0; break; +#endif + default: goto show_usage; + } + + /* grab the <#> portion */ + ulong pin = simple_strtoul(str_pin + 1, NULL, 10); + if (pin > 15) + goto show_usage; + + /* grab the pin before we tweak it */ + ulong gpio = port_base + pin; + gpio_request(gpio, "cmd_gpio"); + + /* finally, let's do it: set direction and exec command */ + if (sub_cmd == GPIO_INPUT) { + gpio_direction_input(gpio); + printf("gpio: pin %lu on port %c set to input\n", pin, *str_pin); + return 0; + } + + ulong value; + switch (sub_cmd) { + case GPIO_SET: value = 1; break; + case GPIO_CLEAR: value = 0; break; + case GPIO_TOGGLE: value = !gpio_get_value(gpio); break; + default: goto show_usage; + } + gpio_direction_output(gpio, value); + printf("gpio: pin %lu on port %c (gpio %lu) value is %lu\n", + pin, *str_pin, gpio, value); + + gpio_free(gpio); + + return 0; +} + +U_BOOT_CMD(gpio, 3, 0, do_gpio, + "set/clear/toggle gpio output pins", + " \n" + " - set/clear/toggle the specified pin (e.g. PF10)"); -- cgit From a409fdd8fe013aa4a4564bedc1f673b9455e64da Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 2 Jun 2010 06:00:27 -0400 Subject: Blackfin: serial: convert to portmux framework Use the new portmux framework to handle the details when possible. Unfortunately, we cannot yet use this in the standalone initialization logic, so we need to keep around the old portmux writes for now. Signed-off-by: Mike Frysinger --- arch/blackfin/cpu/serial.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'arch/blackfin/cpu') diff --git a/arch/blackfin/cpu/serial.h b/arch/blackfin/cpu/serial.h index 5f9be8622d..f9e311f3ee 100644 --- a/arch/blackfin/cpu/serial.h +++ b/arch/blackfin/cpu/serial.h @@ -26,6 +26,8 @@ #ifndef __ASSEMBLY__ +#include + #define LOB(x) ((x) & 0xFF) #define HIB(x) (((x) >> 8) & 0xFF) @@ -103,6 +105,23 @@ struct bfin_mmr_serial { __attribute__((always_inline)) static inline void serial_do_portmux(void) { + if (!BFIN_DEBUG_EARLY_SERIAL) { + const unsigned short pins[] = { +#if CONFIG_UART_CONSOLE == 0 + P_UART0_TX, P_UART0_RX, +#elif CONFIG_UART_CONSOLE == 1 + P_UART1_TX, P_UART1_RX, +#elif CONFIG_UART_CONSOLE == 2 + P_UART2_TX, P_UART2_RX, +#elif CONFIG_UART_CONSOLE == 3 + P_UART3_TX, P_UART3_RX, +#endif + 0, + }; + peripheral_request_list(pins, "bfin-uart"); + return; + } + #if defined(__ADSPBF51x__) # define DO_MUX(port, mux_tx, mux_rx, tx, rx) \ bfin_write_PORT##port##_MUX((bfin_read_PORT##port##_MUX() & ~(PORT_x_MUX_##mux_tx##_MASK | PORT_x_MUX_##mux_rx##_MASK)) | PORT_x_MUX_##mux_tx##_FUNC_2 | PORT_x_MUX_##mux_rx##_FUNC_2); \ -- cgit