diff options
Diffstat (limited to 'arch/arm/mach-uniphier/micro-support-card.c')
-rw-r--r-- | arch/arm/mach-uniphier/micro-support-card.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/arch/arm/mach-uniphier/micro-support-card.c b/arch/arm/mach-uniphier/micro-support-card.c new file mode 100644 index 0000000000..4c34748c25 --- /dev/null +++ b/arch/arm/mach-uniphier/micro-support-card.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012-2015 Masahiro Yamada <yamada.masahiro@socionext.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <linux/ctype.h> +#include <linux/io.h> +#include <mach/micro-support-card.h> + +#define MICRO_SUPPORT_CARD_BASE 0x43f00000 +#define SMC911X_BASE ((MICRO_SUPPORT_CARD_BASE) + 0x00000) +#define LED_BASE ((MICRO_SUPPORT_CARD_BASE) + 0x90000) +#define NS16550A_BASE ((MICRO_SUPPORT_CARD_BASE) + 0xb0000) +#define MICRO_SUPPORT_CARD_RESET ((MICRO_SUPPORT_CARD_BASE) + 0xd0034) +#define MICRO_SUPPORT_CARD_REVISION ((MICRO_SUPPORT_CARD_BASE) + 0xd00E0) + +/* + * 0: reset deassert, 1: reset + * + * bit[0]: LAN, I2C, LED + * bit[1]: UART + */ +void support_card_reset_deassert(void) +{ + writel(0, MICRO_SUPPORT_CARD_RESET); +} + +void support_card_reset(void) +{ + writel(3, MICRO_SUPPORT_CARD_RESET); +} + +static int support_card_show_revision(void) +{ + u32 revision; + + revision = readl(MICRO_SUPPORT_CARD_REVISION); + printf("(CPLD version %d.%d)\n", revision >> 4, revision & 0xf); + return 0; +} + +int check_support_card(void) +{ + printf("SC: Micro Support Card "); + return support_card_show_revision(); +} + +void support_card_init(void) +{ + /* + * After power on, we need to keep the LAN controller in reset state + * for a while. (200 usec) + * Fortunately, enough wait time is already inserted in pll_init() + * function. So we do not have to wait here. + */ + support_card_reset_deassert(); +} + +#if defined(CONFIG_SMC911X) +#include <netdev.h> + +int board_eth_init(bd_t *bis) +{ + return smc911x_initialize(0, SMC911X_BASE); +} +#endif + +#if !defined(CONFIG_SYS_NO_FLASH) + +#include <mtd/cfi_flash.h> +#include <mach/sbc-regs.h> + +struct memory_bank { + phys_addr_t base; + unsigned long size; +}; + +static int mem_is_flash(const struct memory_bank *mem) +{ + const int loop = 128; + u32 *scratch_addr; + u32 saved_value; + int ret = 1; + int i; + + /* just in case, use the tail of the memory bank */ + scratch_addr = map_physmem(mem->base + mem->size - sizeof(u32) * loop, + sizeof(u32) * loop, MAP_NOCACHE); + + for (i = 0; i < loop; i++, scratch_addr++) { + saved_value = readl(scratch_addr); + writel(~saved_value, scratch_addr); + if (readl(scratch_addr) != saved_value) { + /* We assume no memory or SRAM here. */ + writel(saved_value, scratch_addr); + ret = 0; + break; + } + } + + unmap_physmem(scratch_addr, MAP_NOCACHE); + + return ret; +} + +/* {address, size} */ +static const struct memory_bank memory_banks[] = { + {0x42000000, 0x01f00000}, +}; + +static const struct memory_bank +*flash_banks_list[CONFIG_SYS_MAX_FLASH_BANKS_DETECT]; + +phys_addr_t cfi_flash_bank_addr(int i) +{ + return flash_banks_list[i]->base; +} + +unsigned long cfi_flash_bank_size(int i) +{ + return flash_banks_list[i]->size; +} + +static void detect_num_flash_banks(void) +{ + const struct memory_bank *memory_bank, *end; + + cfi_flash_num_flash_banks = 0; + + memory_bank = memory_banks; + end = memory_bank + ARRAY_SIZE(memory_banks); + + for (; memory_bank < end; memory_bank++) { + if (cfi_flash_num_flash_banks >= + CONFIG_SYS_MAX_FLASH_BANKS_DETECT) + break; + + if (mem_is_flash(memory_bank)) { + flash_banks_list[cfi_flash_num_flash_banks] = + memory_bank; + + debug("flash bank found: base = 0x%lx, size = 0x%lx\n", + memory_bank->base, memory_bank->size); + cfi_flash_num_flash_banks++; + } + } + + debug("number of flash banks: %d\n", cfi_flash_num_flash_banks); +} +#else /* CONFIG_SYS_NO_FLASH */ +void detect_num_flash_banks(void) +{ +}; +#endif /* CONFIG_SYS_NO_FLASH */ + +void support_card_late_init(void) +{ + detect_num_flash_banks(); +} + +static const u8 ledval_num[] = { + 0x7e, /* 0 */ + 0x0c, /* 1 */ + 0xb6, /* 2 */ + 0x9e, /* 3 */ + 0xcc, /* 4 */ + 0xda, /* 5 */ + 0xfa, /* 6 */ + 0x4e, /* 7 */ + 0xfe, /* 8 */ + 0xde, /* 9 */ +}; + +static const u8 ledval_alpha[] = { + 0xee, /* A */ + 0xf8, /* B */ + 0x72, /* C */ + 0xbc, /* D */ + 0xf2, /* E */ + 0xe2, /* F */ + 0x7a, /* G */ + 0xe8, /* H */ + 0x08, /* I */ + 0x3c, /* J */ + 0xea, /* K */ + 0x70, /* L */ + 0x6e, /* M */ + 0xa8, /* N */ + 0xb8, /* O */ + 0xe6, /* P */ + 0xce, /* Q */ + 0xa0, /* R */ + 0xc8, /* S */ + 0x8c, /* T */ + 0x7c, /* U */ + 0x54, /* V */ + 0xfc, /* W */ + 0xec, /* X */ + 0xdc, /* Y */ + 0xa4, /* Z */ +}; + +static u8 char2ledval(char c) +{ + if (isdigit(c)) + return ledval_num[c - '0']; + else if (isalpha(c)) + return ledval_alpha[toupper(c) - 'A']; + + return 0; +} + +void led_puts(const char *s) +{ + int i; + u32 val = 0; + + if (!s) + return; + + for (i = 0; i < 4; i++) { + val <<= 8; + val |= char2ledval(*s); + if (*s != '\0') + s++; + } + + writel(~val, LED_BASE); +} |