1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2012-2015 Panasonic Corporation
4 * Copyright (C) 2015-2020 Socionext Inc.
5 * Author: Masahiro Yamada <yamada.masahiro@socionext.com>
10 #include <fdt_support.h>
11 #include <linux/ctype.h>
14 #include "micro-support-card.h"
16 #define SMC911X_OFFSET 0x00000
17 #define LED_OFFSET 0x90000
18 #define NS16550A_OFFSET 0xb0000
19 #define MICRO_SUPPORT_CARD_RESET 0xd0034
20 #define MICRO_SUPPORT_CARD_REVISION 0xd00e0
22 static bool support_card_found
;
23 static void __iomem
*support_card_base
;
25 static void support_card_detect(void)
27 DECLARE_GLOBAL_DATA_PTR
;
28 const void *fdt
= gd
->fdt_blob
;
32 offset
= fdt_node_offset_by_compatible(fdt
, 0, "smsc,lan9118");
36 addr
= fdt_get_base_address(fdt
, offset
);
37 if (addr
== OF_BAD_ADDR
)
39 addr
-= SMC911X_OFFSET
;
41 offset
= fdt_node_offset_by_compatible(fdt
, 0, "ns16550a");
45 addr2
= fdt_get_base_address(fdt
, offset
);
46 if (addr2
== OF_BAD_ADDR
)
48 addr2
-= NS16550A_OFFSET
;
54 support_card_base
= ioremap(addr
, 0x100000);
56 support_card_found
= true;
60 * 0: reset deassert, 1: reset
62 * bit[0]: LAN, I2C, LED
65 static void support_card_reset_deassert(void)
67 writel(0x00010000, support_card_base
+ MICRO_SUPPORT_CARD_RESET
);
70 static void support_card_reset(void)
72 writel(0x00020003, support_card_base
+ MICRO_SUPPORT_CARD_RESET
);
75 static int support_card_show_revision(void)
79 revision
= readl(support_card_base
+ MICRO_SUPPORT_CARD_REVISION
);
82 /* revision 3.6.x card changed the revision format */
83 printf("SC: Micro Support Card (CPLD version %s%d.%d)\n",
84 revision
>> 4 == 6 ? "3." : "",
85 revision
>> 4, revision
& 0xf);
90 void support_card_init(void)
92 support_card_detect();
94 if (!support_card_found
)
99 * After power on, we need to keep the LAN controller in reset state
100 * for a while. (200 usec)
103 support_card_reset_deassert();
105 support_card_show_revision();
108 #if defined(CONFIG_SMC911X)
111 int board_eth_init(bd_t
*bis
)
113 if (!support_card_found
)
116 return smc911x_initialize(0, (unsigned long)support_card_base
+ SMC911X_OFFSET
);
120 #if defined(CONFIG_MTD_NOR_FLASH)
122 #include <mtd/cfi_flash.h>
129 static int mem_is_flash(const struct memory_bank
*mem
)
131 const int loop
= 128;
137 /* just in case, use the tail of the memory bank */
138 scratch_addr
= map_physmem(mem
->base
+ mem
->size
- sizeof(u32
) * loop
,
139 sizeof(u32
) * loop
, MAP_NOCACHE
);
141 for (i
= 0; i
< loop
; i
++, scratch_addr
++) {
142 saved_value
= readl(scratch_addr
);
143 writel(~saved_value
, scratch_addr
);
144 if (readl(scratch_addr
) != saved_value
) {
145 /* We assume no memory or SRAM here. */
146 writel(saved_value
, scratch_addr
);
152 unmap_physmem(scratch_addr
, MAP_NOCACHE
);
157 /* {address, size} */
158 static const struct memory_bank memory_banks
[] = {
159 {0x42000000, 0x01f00000},
162 static const struct memory_bank
163 *flash_banks_list
[CONFIG_SYS_MAX_FLASH_BANKS_DETECT
];
165 phys_addr_t
cfi_flash_bank_addr(int i
)
167 return flash_banks_list
[i
]->base
;
170 unsigned long cfi_flash_bank_size(int i
)
172 return flash_banks_list
[i
]->size
;
175 static void detect_num_flash_banks(void)
177 const struct memory_bank
*memory_bank
, *end
;
179 cfi_flash_num_flash_banks
= 0;
181 memory_bank
= memory_banks
;
182 end
= memory_bank
+ ARRAY_SIZE(memory_banks
);
184 for (; memory_bank
< end
; memory_bank
++) {
185 if (cfi_flash_num_flash_banks
>=
186 CONFIG_SYS_MAX_FLASH_BANKS_DETECT
)
189 if (mem_is_flash(memory_bank
)) {
190 flash_banks_list
[cfi_flash_num_flash_banks
] =
193 debug("flash bank found: base = 0x%lx, size = 0x%lx\n",
194 (unsigned long)memory_bank
->base
,
195 (unsigned long)memory_bank
->size
);
196 cfi_flash_num_flash_banks
++;
200 debug("number of flash banks: %d\n", cfi_flash_num_flash_banks
);
202 #else /* CONFIG_MTD_NOR_FLASH */
203 static void detect_num_flash_banks(void)
206 #endif /* CONFIG_MTD_NOR_FLASH */
208 void support_card_late_init(void)
210 if (!support_card_found
)
213 detect_num_flash_banks();
216 static const u8 ledval_num
[] = {
229 static const u8 ledval_alpha
[] = {
258 static u8
char2ledval(char c
)
261 return ledval_num
[c
- '0'];
263 return ledval_alpha
[toupper(c
) - 'A'];
268 void led_puts(const char *s
)
273 if (!support_card_found
)
279 for (i
= 0; i
< 4; i
++) {
281 val
|= char2ledval(*s
);
286 writel(~val
, support_card_base
+ LED_OFFSET
);