root/arch/mips/generic/yamon-dt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. yamon_dt_append_cmdline
  2. gen_fdt_mem_array
  3. yamon_dt_append_memory
  4. yamon_dt_serial_config

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2016 Imagination Technologies
   4  * Author: Paul Burton <paul.burton@mips.com>
   5  */
   6 
   7 #define pr_fmt(fmt) "yamon-dt: " fmt
   8 
   9 #include <linux/bug.h>
  10 #include <linux/errno.h>
  11 #include <linux/kernel.h>
  12 #include <linux/libfdt.h>
  13 #include <linux/printk.h>
  14 
  15 #include <asm/fw/fw.h>
  16 #include <asm/yamon-dt.h>
  17 
  18 #define MAX_MEM_ARRAY_ENTRIES   2
  19 
  20 __init int yamon_dt_append_cmdline(void *fdt)
  21 {
  22         int err, chosen_off;
  23 
  24         /* find or add chosen node */
  25         chosen_off = fdt_path_offset(fdt, "/chosen");
  26         if (chosen_off == -FDT_ERR_NOTFOUND)
  27                 chosen_off = fdt_add_subnode(fdt, 0, "chosen");
  28         if (chosen_off < 0) {
  29                 pr_err("Unable to find or add DT chosen node: %d\n",
  30                        chosen_off);
  31                 return chosen_off;
  32         }
  33 
  34         err = fdt_setprop_string(fdt, chosen_off, "bootargs", fw_getcmdline());
  35         if (err) {
  36                 pr_err("Unable to set bootargs property: %d\n", err);
  37                 return err;
  38         }
  39 
  40         return 0;
  41 }
  42 
  43 static unsigned int __init gen_fdt_mem_array(
  44                                         const struct yamon_mem_region *regions,
  45                                         __be32 *mem_array,
  46                                         unsigned int max_entries,
  47                                         unsigned long memsize)
  48 {
  49         const struct yamon_mem_region *mr;
  50         unsigned long size;
  51         unsigned int entries = 0;
  52 
  53         for (mr = regions; mr->size && memsize; ++mr) {
  54                 if (entries >= max_entries) {
  55                         pr_warn("Number of regions exceeds max %u\n",
  56                                 max_entries);
  57                         break;
  58                 }
  59 
  60                 /* How much of the remaining RAM fits in the next region? */
  61                 size = min_t(unsigned long, memsize, mr->size);
  62                 memsize -= size;
  63 
  64                 /* Emit a memory region */
  65                 *(mem_array++) = cpu_to_be32(mr->start);
  66                 *(mem_array++) = cpu_to_be32(size);
  67                 ++entries;
  68 
  69                 /* Discard the next mr->discard bytes */
  70                 memsize -= min_t(unsigned long, memsize, mr->discard);
  71         }
  72         return entries;
  73 }
  74 
  75 __init int yamon_dt_append_memory(void *fdt,
  76                                   const struct yamon_mem_region *regions)
  77 {
  78         unsigned long phys_memsize, memsize;
  79         __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
  80         unsigned int mem_entries;
  81         int i, err, mem_off;
  82         char *var, param_name[10], *var_names[] = {
  83                 "ememsize", "memsize",
  84         };
  85 
  86         /* find memory size from the bootloader environment */
  87         for (i = 0; i < ARRAY_SIZE(var_names); i++) {
  88                 var = fw_getenv(var_names[i]);
  89                 if (!var)
  90                         continue;
  91 
  92                 err = kstrtoul(var, 0, &phys_memsize);
  93                 if (!err)
  94                         break;
  95 
  96                 pr_warn("Failed to read the '%s' env variable '%s'\n",
  97                         var_names[i], var);
  98         }
  99 
 100         if (!phys_memsize) {
 101                 pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
 102                 phys_memsize = 32 << 20;
 103         }
 104 
 105         /* default to using all available RAM */
 106         memsize = phys_memsize;
 107 
 108         /* allow the user to override the usable memory */
 109         for (i = 0; i < ARRAY_SIZE(var_names); i++) {
 110                 snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
 111                 var = strstr(arcs_cmdline, param_name);
 112                 if (!var)
 113                         continue;
 114 
 115                 memsize = memparse(var + strlen(param_name), NULL);
 116         }
 117 
 118         /* if the user says there's more RAM than we thought, believe them */
 119         phys_memsize = max_t(unsigned long, phys_memsize, memsize);
 120 
 121         /* find or add a memory node */
 122         mem_off = fdt_path_offset(fdt, "/memory");
 123         if (mem_off == -FDT_ERR_NOTFOUND)
 124                 mem_off = fdt_add_subnode(fdt, 0, "memory");
 125         if (mem_off < 0) {
 126                 pr_err("Unable to find or add memory DT node: %d\n", mem_off);
 127                 return mem_off;
 128         }
 129 
 130         err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
 131         if (err) {
 132                 pr_err("Unable to set memory node device_type: %d\n", err);
 133                 return err;
 134         }
 135 
 136         mem_entries = gen_fdt_mem_array(regions, mem_array,
 137                                         MAX_MEM_ARRAY_ENTRIES, phys_memsize);
 138         err = fdt_setprop(fdt, mem_off, "reg",
 139                           mem_array, mem_entries * 2 * sizeof(mem_array[0]));
 140         if (err) {
 141                 pr_err("Unable to set memory regs property: %d\n", err);
 142                 return err;
 143         }
 144 
 145         mem_entries = gen_fdt_mem_array(regions, mem_array,
 146                                         MAX_MEM_ARRAY_ENTRIES, memsize);
 147         err = fdt_setprop(fdt, mem_off, "linux,usable-memory",
 148                           mem_array, mem_entries * 2 * sizeof(mem_array[0]));
 149         if (err) {
 150                 pr_err("Unable to set linux,usable-memory property: %d\n", err);
 151                 return err;
 152         }
 153 
 154         return 0;
 155 }
 156 
 157 __init int yamon_dt_serial_config(void *fdt)
 158 {
 159         const char *yamontty, *mode_var;
 160         char mode_var_name[9], path[20], parity;
 161         unsigned int uart, baud, stop_bits;
 162         bool hw_flow;
 163         int chosen_off, err;
 164 
 165         yamontty = fw_getenv("yamontty");
 166         if (!yamontty || !strcmp(yamontty, "tty0")) {
 167                 uart = 0;
 168         } else if (!strcmp(yamontty, "tty1")) {
 169                 uart = 1;
 170         } else {
 171                 pr_warn("yamontty environment variable '%s' invalid\n",
 172                         yamontty);
 173                 uart = 0;
 174         }
 175 
 176         baud = stop_bits = 0;
 177         parity = 0;
 178         hw_flow = false;
 179 
 180         snprintf(mode_var_name, sizeof(mode_var_name), "modetty%u", uart);
 181         mode_var = fw_getenv(mode_var_name);
 182         if (mode_var) {
 183                 while (mode_var[0] >= '0' && mode_var[0] <= '9') {
 184                         baud *= 10;
 185                         baud += mode_var[0] - '0';
 186                         mode_var++;
 187                 }
 188                 if (mode_var[0] == ',')
 189                         mode_var++;
 190                 if (mode_var[0])
 191                         parity = mode_var[0];
 192                 if (mode_var[0] == ',')
 193                         mode_var++;
 194                 if (mode_var[0])
 195                         stop_bits = mode_var[0] - '0';
 196                 if (mode_var[0] == ',')
 197                         mode_var++;
 198                 if (!strcmp(mode_var, "hw"))
 199                         hw_flow = true;
 200         }
 201 
 202         if (!baud)
 203                 baud = 38400;
 204 
 205         if (parity != 'e' && parity != 'n' && parity != 'o')
 206                 parity = 'n';
 207 
 208         if (stop_bits != 7 && stop_bits != 8)
 209                 stop_bits = 8;
 210 
 211         WARN_ON(snprintf(path, sizeof(path), "serial%u:%u%c%u%s",
 212                          uart, baud, parity, stop_bits,
 213                          hw_flow ? "r" : "") >= sizeof(path));
 214 
 215         /* find or add chosen node */
 216         chosen_off = fdt_path_offset(fdt, "/chosen");
 217         if (chosen_off == -FDT_ERR_NOTFOUND)
 218                 chosen_off = fdt_add_subnode(fdt, 0, "chosen");
 219         if (chosen_off < 0) {
 220                 pr_err("Unable to find or add DT chosen node: %d\n",
 221                        chosen_off);
 222                 return chosen_off;
 223         }
 224 
 225         err = fdt_setprop_string(fdt, chosen_off, "stdout-path", path);
 226         if (err) {
 227                 pr_err("Unable to set stdout-path property: %d\n", err);
 228                 return err;
 229         }
 230 
 231         return 0;
 232 }

/* [<][>][^][v][top][bottom][index][help] */