linux/arch/mips/ar7/prom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Carsten Langgaard, carstenl@mips.com
   4 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
   5 *
   6 * Putting things on the screen/serial line using YAMONs facilities.
   7 */
   8#include <linux/init.h>
   9#include <linux/kernel.h>
  10#include <linux/serial_reg.h>
  11#include <linux/spinlock.h>
  12#include <linux/export.h>
  13#include <linux/string.h>
  14#include <linux/io.h>
  15#include <asm/bootinfo.h>
  16#include <asm/setup.h>
  17
  18#include <asm/mach-ar7/ar7.h>
  19#include <asm/mach-ar7/prom.h>
  20
  21#define MAX_ENTRY 80
  22
  23struct env_var {
  24        char    *name;
  25        char    *value;
  26};
  27
  28static struct env_var adam2_env[MAX_ENTRY];
  29
  30char *prom_getenv(const char *name)
  31{
  32        int i;
  33
  34        for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
  35                if (!strcmp(name, adam2_env[i].name))
  36                        return adam2_env[i].value;
  37
  38        return NULL;
  39}
  40EXPORT_SYMBOL(prom_getenv);
  41
  42static void  __init ar7_init_cmdline(int argc, char *argv[])
  43{
  44        int i;
  45
  46        for (i = 1; i < argc; i++) {
  47                strlcat(arcs_cmdline, argv[i], COMMAND_LINE_SIZE);
  48                if (i < (argc - 1))
  49                        strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
  50        }
  51}
  52
  53struct psbl_rec {
  54        u32     psbl_size;
  55        u32     env_base;
  56        u32     env_size;
  57        u32     ffs_base;
  58        u32     ffs_size;
  59};
  60
  61static const char psp_env_version[] __initconst = "TIENV0.8";
  62
  63struct psp_env_chunk {
  64        u8      num;
  65        u8      ctrl;
  66        u16     csum;
  67        u8      len;
  68        char    data[11];
  69} __packed;
  70
  71struct psp_var_map_entry {
  72        u8      num;
  73        char    *value;
  74};
  75
  76static const struct psp_var_map_entry psp_var_map[] = {
  77        {  1,   "cpufrequency" },
  78        {  2,   "memsize" },
  79        {  3,   "flashsize" },
  80        {  4,   "modetty0" },
  81        {  5,   "modetty1" },
  82        {  8,   "maca" },
  83        {  9,   "macb" },
  84        { 28,   "sysfrequency" },
  85        { 38,   "mipsfrequency" },
  86};
  87
  88/*
  89
  90Well-known variable (num is looked up in table above for matching variable name)
  91Example: cpufrequency=211968000
  92+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
  93| 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF
  94+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
  95
  96Name=Value pair in a single chunk
  97Example: NAME=VALUE
  98+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
  99| 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0
 100+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 101
 102Name=Value pair in 2 chunks (len is the number of chunks)
 103Example: bootloaderVersion=1.3.7.15
 104+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 105| 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
 106+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 107| _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0
 108+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 109
 110Data is padded with 0xFF
 111
 112*/
 113
 114#define PSP_ENV_SIZE  4096
 115
 116static char psp_env_data[PSP_ENV_SIZE] = { 0, };
 117
 118static char * __init lookup_psp_var_map(u8 num)
 119{
 120        int i;
 121
 122        for (i = 0; i < ARRAY_SIZE(psp_var_map); i++)
 123                if (psp_var_map[i].num == num)
 124                        return psp_var_map[i].value;
 125
 126        return NULL;
 127}
 128
 129static void __init add_adam2_var(char *name, char *value)
 130{
 131        int i;
 132
 133        for (i = 0; i < MAX_ENTRY; i++) {
 134                if (!adam2_env[i].name) {
 135                        adam2_env[i].name = name;
 136                        adam2_env[i].value = value;
 137                        return;
 138                } else if (!strcmp(adam2_env[i].name, name)) {
 139                        adam2_env[i].value = value;
 140                        return;
 141                }
 142        }
 143}
 144
 145static int __init parse_psp_env(void *psp_env_base)
 146{
 147        int i, n;
 148        char *name, *value;
 149        struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
 150
 151        memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
 152
 153        i = 1;
 154        n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
 155        while (i < n) {
 156                if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
 157                        break;
 158                value = chunks[i].data;
 159                if (chunks[i].num) {
 160                        name = lookup_psp_var_map(chunks[i].num);
 161                } else {
 162                        name = value;
 163                        value += strlen(name) + 1;
 164                }
 165                if (name)
 166                        add_adam2_var(name, value);
 167                i += chunks[i].len;
 168        }
 169        return 0;
 170}
 171
 172static void __init ar7_init_env(struct env_var *env)
 173{
 174        int i;
 175        struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
 176        void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
 177
 178        if (strcmp(psp_env, psp_env_version) == 0) {
 179                parse_psp_env(psp_env);
 180        } else {
 181                for (i = 0; i < MAX_ENTRY; i++, env++)
 182                        if (env->name)
 183                                add_adam2_var(env->name, env->value);
 184        }
 185}
 186
 187static void __init console_config(void)
 188{
 189#ifdef CONFIG_SERIAL_8250_CONSOLE
 190        char console_string[40];
 191        int baud = 0;
 192        char parity = '\0', bits = '\0', flow = '\0';
 193        char *s, *p;
 194
 195        if (strstr(arcs_cmdline, "console="))
 196                return;
 197
 198        s = prom_getenv("modetty0");
 199        if (s) {
 200                baud = simple_strtoul(s, &p, 10);
 201                s = p;
 202                if (*s == ',')
 203                        s++;
 204                if (*s)
 205                        parity = *s++;
 206                if (*s == ',')
 207                        s++;
 208                if (*s)
 209                        bits = *s++;
 210                if (*s == ',')
 211                        s++;
 212                if (*s == 'h')
 213                        flow = 'r';
 214        }
 215
 216        if (baud == 0)
 217                baud = 38400;
 218        if (parity != 'n' && parity != 'o' && parity != 'e')
 219                parity = 'n';
 220        if (bits != '7' && bits != '8')
 221                bits = '8';
 222
 223        if (flow == 'r')
 224                sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
 225                        parity, bits, flow);
 226        else
 227                sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
 228                        bits);
 229        strlcat(arcs_cmdline, console_string, COMMAND_LINE_SIZE);
 230#endif
 231}
 232
 233void __init prom_init(void)
 234{
 235        ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
 236        ar7_init_env((struct env_var *)fw_arg2);
 237        console_config();
 238}
 239
 240#define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
 241static inline unsigned int serial_in(int offset)
 242{
 243        return readl((void *)PORT(offset));
 244}
 245
 246static inline void serial_out(int offset, int value)
 247{
 248        writel(value, (void *)PORT(offset));
 249}
 250
 251void prom_putchar(char c)
 252{
 253        while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
 254                ;
 255        serial_out(UART_TX, c);
 256}
 257