root/arch/powerpc/boot/cpm-serial.c

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

DEFINITIONS

This source file includes following definitions.
  1. cpm1_cmd
  2. cpm2_cmd
  3. smc_disable_port
  4. scc_disable_port
  5. smc_enable_port
  6. scc_enable_port
  7. cpm_serial_open
  8. cpm_serial_putc
  9. cpm_serial_tstc
  10. cpm_serial_getc
  11. cpm_console_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * CPM serial console support.
   4  *
   5  * Copyright 2007 Freescale Semiconductor, Inc.
   6  * Author: Scott Wood <scottwood@freescale.com>
   7  *
   8  * It is assumed that the firmware (or the platform file) has already set
   9  * up the port.
  10  */
  11 
  12 #include "types.h"
  13 #include "io.h"
  14 #include "ops.h"
  15 #include "page.h"
  16 
  17 struct cpm_scc {
  18         u32 gsmrl;
  19         u32 gsmrh;
  20         u16 psmr;
  21         u8 res1[2];
  22         u16 todr;
  23         u16 dsr;
  24         u16 scce;
  25         u8 res2[2];
  26         u16 sccm;
  27         u8 res3;
  28         u8 sccs;
  29         u8 res4[8];
  30 };
  31 
  32 struct cpm_smc {
  33         u8 res1[2];
  34         u16 smcmr;
  35         u8 res2[2];
  36         u8 smce;
  37         u8 res3[3];
  38         u8 smcm;
  39         u8 res4[5];
  40 };
  41 
  42 struct cpm_param {
  43         u16 rbase;
  44         u16 tbase;
  45         u8 rfcr;
  46         u8 tfcr;
  47         u16 mrblr;
  48         u32 rstate;
  49         u8 res1[4];
  50         u16 rbptr;
  51         u8 res2[6];
  52         u32 tstate;
  53         u8 res3[4];
  54         u16 tbptr;
  55         u8 res4[6];
  56         u16 maxidl;
  57         u16 idlc;
  58         u16 brkln;
  59         u16 brkec;
  60         u16 brkcr;
  61         u16 rmask;
  62         u8 res5[4];
  63 };
  64 
  65 struct cpm_bd {
  66         u16 sc;   /* Status and Control */
  67         u16 len;  /* Data length in buffer */
  68         u8 *addr; /* Buffer address in host memory */
  69 };
  70 
  71 static void *cpcr;
  72 static struct cpm_param *param;
  73 static struct cpm_smc *smc;
  74 static struct cpm_scc *scc;
  75 static struct cpm_bd *tbdf, *rbdf;
  76 static u32 cpm_cmd;
  77 static void *cbd_addr;
  78 static u32 cbd_offset;
  79 
  80 static void (*do_cmd)(int op);
  81 static void (*enable_port)(void);
  82 static void (*disable_port)(void);
  83 
  84 #define CPM_CMD_STOP_TX     4
  85 #define CPM_CMD_RESTART_TX  6
  86 #define CPM_CMD_INIT_RX_TX  0
  87 
  88 static void cpm1_cmd(int op)
  89 {
  90         while (in_be16(cpcr) & 1)
  91                 ;
  92 
  93         out_be16(cpcr, (op << 8) | cpm_cmd | 1);
  94 
  95         while (in_be16(cpcr) & 1)
  96                 ;
  97 }
  98 
  99 static void cpm2_cmd(int op)
 100 {
 101         while (in_be32(cpcr) & 0x10000)
 102                 ;
 103 
 104         out_be32(cpcr, op | cpm_cmd | 0x10000);
 105 
 106         while (in_be32(cpcr) & 0x10000)
 107                 ;
 108 }
 109 
 110 static void smc_disable_port(void)
 111 {
 112         do_cmd(CPM_CMD_STOP_TX);
 113         out_be16(&smc->smcmr, in_be16(&smc->smcmr) & ~3);
 114 }
 115 
 116 static void scc_disable_port(void)
 117 {
 118         do_cmd(CPM_CMD_STOP_TX);
 119         out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) & ~0x30);
 120 }
 121 
 122 static void smc_enable_port(void)
 123 {
 124         out_be16(&smc->smcmr, in_be16(&smc->smcmr) | 3);
 125         do_cmd(CPM_CMD_RESTART_TX);
 126 }
 127 
 128 static void scc_enable_port(void)
 129 {
 130         out_be32(&scc->gsmrl, in_be32(&scc->gsmrl) | 0x30);
 131         do_cmd(CPM_CMD_RESTART_TX);
 132 }
 133 
 134 static int cpm_serial_open(void)
 135 {
 136         disable_port();
 137 
 138         out_8(&param->rfcr, 0x10);
 139         out_8(&param->tfcr, 0x10);
 140         out_be16(&param->mrblr, 1);
 141         out_be16(&param->maxidl, 0);
 142         out_be16(&param->brkec, 0);
 143         out_be16(&param->brkln, 0);
 144         out_be16(&param->brkcr, 0);
 145 
 146         rbdf = cbd_addr;
 147         rbdf->addr = (u8 *)rbdf - 1;
 148         rbdf->sc = 0xa000;
 149         rbdf->len = 1;
 150 
 151         tbdf = rbdf + 1;
 152         tbdf->addr = (u8 *)rbdf - 2;
 153         tbdf->sc = 0x2000;
 154         tbdf->len = 1;
 155 
 156         sync();
 157         out_be16(&param->rbase, cbd_offset);
 158         out_be16(&param->tbase, cbd_offset + sizeof(struct cpm_bd));
 159 
 160         do_cmd(CPM_CMD_INIT_RX_TX);
 161 
 162         enable_port();
 163         return 0;
 164 }
 165 
 166 static void cpm_serial_putc(unsigned char c)
 167 {
 168         while (tbdf->sc & 0x8000)
 169                 barrier();
 170 
 171         sync();
 172 
 173         tbdf->addr[0] = c;
 174         eieio();
 175         tbdf->sc |= 0x8000;
 176 }
 177 
 178 static unsigned char cpm_serial_tstc(void)
 179 {
 180         barrier();
 181         return !(rbdf->sc & 0x8000);
 182 }
 183 
 184 static unsigned char cpm_serial_getc(void)
 185 {
 186         unsigned char c;
 187 
 188         while (!cpm_serial_tstc())
 189                 ;
 190 
 191         sync();
 192         c = rbdf->addr[0];
 193         eieio();
 194         rbdf->sc |= 0x8000;
 195 
 196         return c;
 197 }
 198 
 199 int cpm_console_init(void *devp, struct serial_console_data *scdp)
 200 {
 201         void *vreg[2];
 202         u32 reg[2];
 203         int is_smc = 0, is_cpm2 = 0;
 204         void *parent, *muram;
 205         void *muram_addr;
 206         unsigned long muram_offset, muram_size;
 207 
 208         if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) {
 209                 is_smc = 1;
 210         } else if (dt_is_compatible(devp, "fsl,cpm2-scc-uart")) {
 211                 is_cpm2 = 1;
 212         } else if (dt_is_compatible(devp, "fsl,cpm2-smc-uart")) {
 213                 is_cpm2 = 1;
 214                 is_smc = 1;
 215         }
 216 
 217         if (is_smc) {
 218                 enable_port = smc_enable_port;
 219                 disable_port = smc_disable_port;
 220         } else {
 221                 enable_port = scc_enable_port;
 222                 disable_port = scc_disable_port;
 223         }
 224 
 225         if (is_cpm2)
 226                 do_cmd = cpm2_cmd;
 227         else
 228                 do_cmd = cpm1_cmd;
 229 
 230         if (getprop(devp, "fsl,cpm-command", &cpm_cmd, 4) < 4)
 231                 return -1;
 232 
 233         if (dt_get_virtual_reg(devp, vreg, 2) < 2)
 234                 return -1;
 235 
 236         if (is_smc)
 237                 smc = vreg[0];
 238         else
 239                 scc = vreg[0];
 240 
 241         param = vreg[1];
 242 
 243         parent = get_parent(devp);
 244         if (!parent)
 245                 return -1;
 246 
 247         if (dt_get_virtual_reg(parent, &cpcr, 1) < 1)
 248                 return -1;
 249 
 250         muram = finddevice("/soc/cpm/muram/data");
 251         if (!muram)
 252                 return -1;
 253 
 254         /* For bootwrapper-compatible device trees, we assume that the first
 255          * entry has at least 128 bytes, and that #address-cells/#data-cells
 256          * is one for both parent and child.
 257          */
 258 
 259         if (dt_get_virtual_reg(muram, &muram_addr, 1) < 1)
 260                 return -1;
 261 
 262         if (getprop(muram, "reg", reg, 8) < 8)
 263                 return -1;
 264 
 265         muram_offset = reg[0];
 266         muram_size = reg[1];
 267 
 268         /* Store the buffer descriptors at the end of the first muram chunk.
 269          * For SMC ports on CPM2-based platforms, relocate the parameter RAM
 270          * just before the buffer descriptors.
 271          */
 272 
 273         cbd_offset = muram_offset + muram_size - 2 * sizeof(struct cpm_bd);
 274 
 275         if (is_cpm2 && is_smc) {
 276                 u16 *smc_base = (u16 *)param;
 277                 u16 pram_offset;
 278 
 279                 pram_offset = cbd_offset - 64;
 280                 pram_offset = _ALIGN_DOWN(pram_offset, 64);
 281 
 282                 disable_port();
 283                 out_be16(smc_base, pram_offset);
 284                 param = muram_addr - muram_offset + pram_offset;
 285         }
 286 
 287         cbd_addr = muram_addr - muram_offset + cbd_offset;
 288 
 289         scdp->open = cpm_serial_open;
 290         scdp->putc = cpm_serial_putc;
 291         scdp->getc = cpm_serial_getc;
 292         scdp->tstc = cpm_serial_tstc;
 293 
 294         return 0;
 295 }

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