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