linux/arch/mips/ar7/prom.c
<<
>>
Prefs
   1/*
   2 * Carsten Langgaard, carstenl@mips.com
   3 * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
   4 *
   5 *  This program is free software; you can distribute it and/or modify it
   6 *  under the terms of the GNU General Public License (Version 2) as
   7 *  published by the Free Software Foundation.
   8 *
   9 *  This program is distributed in the hope it will be useful, but WITHOUT
  10 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12 *  for more details.
  13 *
  14 *  You should have received a copy of the GNU General Public License along
  15 *  with this program; if not, write to the Free Software Foundation, Inc.,
  16 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  17 *
  18 * Putting things on the screen/serial line using YAMONs facilities.
  19 */
  20#include <linux/init.h>
  21#include <linux/kernel.h>
  22#include <linux/serial_reg.h>
  23#include <linux/spinlock.h>
  24#include <linux/module.h>
  25#include <linux/string.h>
  26#include <linux/io.h>
  27#include <asm/bootinfo.h>
  28
  29#include <asm/mach-ar7/ar7.h>
  30#include <asm/mach-ar7/prom.h>
  31
  32#define MAX_ENTRY 80
  33
  34struct env_var {
  35        char *name;
  36        char *value;
  37};
  38
  39static struct env_var adam2_env[MAX_ENTRY];
  40
  41char *prom_getenv(const char *name)
  42{
  43        int i;
  44        for (i = 0; (i < MAX_ENTRY) && adam2_env[i].name; i++)
  45                if (!strcmp(name, adam2_env[i].name))
  46                        return adam2_env[i].value;
  47
  48        return NULL;
  49}
  50EXPORT_SYMBOL(prom_getenv);
  51
  52char * __init prom_getcmdline(void)
  53{
  54        return &(arcs_cmdline[0]);
  55}
  56
  57static void  __init ar7_init_cmdline(int argc, char *argv[])
  58{
  59        char *cp;
  60        int actr;
  61
  62        actr = 1; /* Always ignore argv[0] */
  63
  64        cp = &(arcs_cmdline[0]);
  65        while (actr < argc) {
  66                strcpy(cp, argv[actr]);
  67                cp += strlen(argv[actr]);
  68                *cp++ = ' ';
  69                actr++;
  70        }
  71        if (cp != &(arcs_cmdline[0])) {
  72                /* get rid of trailing space */
  73                --cp;
  74                *cp = '\0';
  75        }
  76}
  77
  78struct psbl_rec {
  79        u32 psbl_size;
  80        u32 env_base;
  81        u32 env_size;
  82        u32 ffs_base;
  83        u32 ffs_size;
  84};
  85
  86static __initdata char psp_env_version[] = "TIENV0.8";
  87
  88struct psp_env_chunk {
  89        u8 num;
  90        u8 ctrl;
  91        u16 csum;
  92        u8 len;
  93        char data[11];
  94} __attribute__ ((packed));
  95
  96struct psp_var_map_entry {
  97        u8 num;
  98        char *value;
  99};
 100
 101static struct psp_var_map_entry psp_var_map[] = {
 102        { 1, "cpufrequency" },
 103        { 2, "memsize" },
 104        { 3, "flashsize" },
 105        { 4, "modetty0" },
 106        { 5, "modetty1" },
 107        { 8, "maca" },
 108        { 9, "macb" },
 109        { 28, "sysfrequency" },
 110        { 38, "mipsfrequency" },
 111};
 112
 113/*
 114
 115Well-known variable (num is looked up in table above for matching variable name)
 116Example: cpufrequency=211968000
 117+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 118| 01 |CTRL|CHECKSUM | 01 | _2 | _1 | _1 | _9 | _6 | _8 | _0 | _0 | _0 | \0 | FF
 119+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 120
 121Name=Value pair in a single chunk
 122Example: NAME=VALUE
 123+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 124| 00 |CTRL|CHECKSUM | 01 | _N | _A | _M | _E | _0 | _V | _A | _L | _U | _E | \0
 125+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 126
 127Name=Value pair in 2 chunks (len is the number of chunks)
 128Example: bootloaderVersion=1.3.7.15
 129+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 130| 00 |CTRL|CHECKSUM | 02 | _b | _o | _o | _t | _l | _o | _a | _d | _e | _r | _V
 131+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 132| _e | _r | _s | _i | _o | _n | \0 | _1 | _. | _3 | _. | _7 | _. | _1 | _5 | \0
 133+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+---
 134
 135Data is padded with 0xFF
 136
 137*/
 138
 139#define PSP_ENV_SIZE  4096
 140
 141static char psp_env_data[PSP_ENV_SIZE] = { 0, };
 142
 143static char * __init lookup_psp_var_map(u8 num)
 144{
 145        int i;
 146
 147        for (i = 0; i < ARRAY_SIZE(psp_var_map); i++)
 148                if (psp_var_map[i].num == num)
 149                        return psp_var_map[i].value;
 150
 151        return NULL;
 152}
 153
 154static void __init add_adam2_var(char *name, char *value)
 155{
 156        int i;
 157        for (i = 0; i < MAX_ENTRY; i++) {
 158                if (!adam2_env[i].name) {
 159                        adam2_env[i].name = name;
 160                        adam2_env[i].value = value;
 161                        return;
 162                } else if (!strcmp(adam2_env[i].name, name)) {
 163                        adam2_env[i].value = value;
 164                        return;
 165                }
 166        }
 167}
 168
 169static int __init parse_psp_env(void *psp_env_base)
 170{
 171        int i, n;
 172        char *name, *value;
 173        struct psp_env_chunk *chunks = (struct psp_env_chunk *)psp_env_data;
 174
 175        memcpy_fromio(chunks, psp_env_base, PSP_ENV_SIZE);
 176
 177        i = 1;
 178        n = PSP_ENV_SIZE / sizeof(struct psp_env_chunk);
 179        while (i < n) {
 180                if ((chunks[i].num == 0xff) || ((i + chunks[i].len) > n))
 181                        break;
 182                value = chunks[i].data;
 183                if (chunks[i].num) {
 184                        name = lookup_psp_var_map(chunks[i].num);
 185                } else {
 186                        name = value;
 187                        value += strlen(name) + 1;
 188                }
 189                if (name)
 190                        add_adam2_var(name, value);
 191                i += chunks[i].len;
 192        }
 193        return 0;
 194}
 195
 196static void __init ar7_init_env(struct env_var *env)
 197{
 198        int i;
 199        struct psbl_rec *psbl = (struct psbl_rec *)(KSEG1ADDR(0x14000300));
 200        void *psp_env = (void *)KSEG1ADDR(psbl->env_base);
 201
 202        if (strcmp(psp_env, psp_env_version) == 0) {
 203                parse_psp_env(psp_env);
 204        } else {
 205                for (i = 0; i < MAX_ENTRY; i++, env++)
 206                        if (env->name)
 207                                add_adam2_var(env->name, env->value);
 208        }
 209}
 210
 211static void __init console_config(void)
 212{
 213#ifdef CONFIG_SERIAL_8250_CONSOLE
 214        char console_string[40];
 215        int baud = 0;
 216        char parity = '\0', bits = '\0', flow = '\0';
 217        char *s, *p;
 218
 219        if (strstr(prom_getcmdline(), "console="))
 220                return;
 221
 222#ifdef CONFIG_KGDB
 223        if (!strstr(prom_getcmdline(), "nokgdb")) {
 224                strcat(prom_getcmdline(), " console=kgdb");
 225                kgdb_enabled = 1;
 226                return;
 227        }
 228#endif
 229
 230        s = prom_getenv("modetty0");
 231        if (s) {
 232                baud = simple_strtoul(s, &p, 10);
 233                s = p;
 234                if (*s == ',')
 235                        s++;
 236                if (*s)
 237                        parity = *s++;
 238                if (*s == ',')
 239                        s++;
 240                if (*s)
 241                        bits = *s++;
 242                if (*s == ',')
 243                        s++;
 244                if (*s == 'h')
 245                        flow = 'r';
 246        }
 247
 248        if (baud == 0)
 249                baud = 38400;
 250        if (parity != 'n' && parity != 'o' && parity != 'e')
 251                parity = 'n';
 252        if (bits != '7' && bits != '8')
 253                bits = '8';
 254
 255        if (flow == 'r')
 256                sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
 257                        parity, bits, flow);
 258        else
 259                sprintf(console_string, " console=ttyS0,%d%c%c", baud, parity,
 260                        bits);
 261        strcat(prom_getcmdline(), console_string);
 262#endif
 263}
 264
 265void __init prom_init(void)
 266{
 267        ar7_init_cmdline(fw_arg0, (char **)fw_arg1);
 268        ar7_init_env((struct env_var *)fw_arg2);
 269        console_config();
 270}
 271
 272#define PORT(offset) (KSEG1ADDR(AR7_REGS_UART0 + (offset * 4)))
 273static inline unsigned int serial_in(int offset)
 274{
 275        return readl((void *)PORT(offset));
 276}
 277
 278static inline void serial_out(int offset, int value)
 279{
 280        writel(value, (void *)PORT(offset));
 281}
 282
 283char prom_getchar(void)
 284{
 285        while (!(serial_in(UART_LSR) & UART_LSR_DR))
 286                ;
 287        return serial_in(UART_RX);
 288}
 289
 290int prom_putchar(char c)
 291{
 292        while ((serial_in(UART_LSR) & UART_LSR_TEMT) == 0)
 293                ;
 294        serial_out(UART_TX, c);
 295        return 1;
 296}
 297
 298