1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2012-2015 Panasonic Corporation 4 * Copyright (C) 2015-2020 Socionext Inc. 5 * Author: Masahiro Yamada <yamada.masahiro@socionext.com> 6 */ 7 8#include <dm.h> 9#include <fdt_support.h> 10#include <linux/ctype.h> 11#include <linux/delay.h> 12#include <linux/io.h> 13#include <asm/global_data.h> 14 15#include "micro-support-card.h" 16 17#define SMC911X_OFFSET 0x00000 18#define LED_OFFSET 0x90000 19#define NS16550A_OFFSET 0xb0000 20#define MICRO_SUPPORT_CARD_RESET 0xd0034 21#define MICRO_SUPPORT_CARD_REVISION 0xd00e0 22 23static bool support_card_found; 24static void __iomem *support_card_base; 25 26static void support_card_detect(void) 27{ 28 DECLARE_GLOBAL_DATA_PTR; 29 const void *fdt = gd->fdt_blob; 30 int offset; 31 u64 addr, addr2; 32 33 offset = fdt_node_offset_by_compatible(fdt, 0, "smsc,lan9118"); 34 if (offset < 0) 35 return; 36 37 addr = fdt_get_base_address(fdt, offset); 38 if (addr == OF_BAD_ADDR) 39 return; 40 addr -= SMC911X_OFFSET; 41 42 offset = fdt_node_offset_by_compatible(fdt, 0, "ns16550a"); 43 if (offset < 0) 44 return; 45 46 addr2 = fdt_get_base_address(fdt, offset); 47 if (addr2 == OF_BAD_ADDR) 48 return; 49 addr2 -= NS16550A_OFFSET; 50 51 /* sanity check */ 52 if (addr != addr2) 53 return; 54 55 support_card_base = ioremap(addr, 0x100000); 56 57 support_card_found = true; 58} 59 60/* 61 * 0: reset deassert, 1: reset 62 * 63 * bit[0]: LAN, I2C, LED 64 * bit[1]: UART 65 */ 66static void support_card_reset_deassert(void) 67{ 68 writel(0x00010000, support_card_base + MICRO_SUPPORT_CARD_RESET); 69} 70 71static void support_card_reset(void) 72{ 73 writel(0x00020003, support_card_base + MICRO_SUPPORT_CARD_RESET); 74} 75 76static int support_card_show_revision(void) 77{ 78 u32 revision; 79 80 revision = readl(support_card_base + MICRO_SUPPORT_CARD_REVISION); 81 revision &= 0xff; 82 83 /* revision 3.6.x card changed the revision format */ 84 printf("SC: Micro Support Card (CPLD version %s%d.%d)\n", 85 revision >> 4 == 6 ? "3." : "", 86 revision >> 4, revision & 0xf); 87 88 return 0; 89} 90 91void support_card_init(void) 92{ 93 struct udevice *dev; 94 int ret; 95 96 /* The system bus must be initialized for access to the support card. */ 97 ret = uclass_get_device_by_driver(UCLASS_SIMPLE_BUS, 98 DM_DRIVER_GET(uniphier_system_bus_driver), 99 &dev); 100 if (ret) 101 return; 102 103 /* Check DT to see if this board has the support card. */ 104 support_card_detect(); 105 106 if (!support_card_found) 107 return; 108 109 support_card_reset(); 110 /* 111 * After power on, we need to keep the LAN controller in reset state 112 * for a while. (200 usec) 113 */ 114 udelay(200); 115 support_card_reset_deassert(); 116 117 support_card_show_revision(); 118} 119 120static const u8 ledval_num[] = { 121 0x7e, /* 0 */ 122 0x0c, /* 1 */ 123 0xb6, /* 2 */ 124 0x9e, /* 3 */ 125 0xcc, /* 4 */ 126 0xda, /* 5 */ 127 0xfa, /* 6 */ 128 0x4e, /* 7 */ 129 0xfe, /* 8 */ 130 0xde, /* 9 */ 131}; 132 133static const u8 ledval_alpha[] = { 134 0xee, /* A */ 135 0xf8, /* B */ 136 0x72, /* C */ 137 0xbc, /* D */ 138 0xf2, /* E */ 139 0xe2, /* F */ 140 0x7a, /* G */ 141 0xe8, /* H */ 142 0x08, /* I */ 143 0x3c, /* J */ 144 0xea, /* K */ 145 0x70, /* L */ 146 0x6e, /* M */ 147 0xa8, /* N */ 148 0xb8, /* O */ 149 0xe6, /* P */ 150 0xce, /* Q */ 151 0xa0, /* R */ 152 0xc8, /* S */ 153 0x8c, /* T */ 154 0x7c, /* U */ 155 0x54, /* V */ 156 0xfc, /* W */ 157 0xec, /* X */ 158 0xdc, /* Y */ 159 0xa4, /* Z */ 160}; 161 162static u8 char2ledval(char c) 163{ 164 if (isdigit(c)) 165 return ledval_num[c - '0']; 166 else if (isalpha(c)) 167 return ledval_alpha[toupper(c) - 'A']; 168 169 return 0; 170} 171 172void led_puts(const char *s) 173{ 174 int i; 175 u32 val = 0; 176 177 if (!support_card_found) 178 return; 179 180 if (!s) 181 return; 182 183 for (i = 0; i < 4; i++) { 184 val <<= 8; 185 val |= char2ledval(*s); 186 if (*s != '\0') 187 s++; 188 } 189 190 writel(~val, support_card_base + LED_OFFSET); 191} 192