uboot/arch/arm/mach-uniphier/micro-support-card.c
<<
>>
Prefs
   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