1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2019 Marvell International Ltd. 4 * Copyright (C) 2021 Stefan Roese <sr@denx.de> 5 */ 6 7#include <dm.h> 8#include <dm/uclass.h> 9#include <errno.h> 10#include <input.h> 11#include <iomux.h> 12#include <log.h> 13#include <serial.h> 14#include <stdio_dev.h> 15#include <string.h> 16#include <watchdog.h> 17#include <linux/delay.h> 18#include <asm/io.h> 19#include <mach/cvmx-regs.h> 20#include <mach/cvmx-bootmem.h> 21 22#define DRIVER_NAME "pci-console" 23#define OCTEONTX_PCIE_CONSOLE_NAME_LEN 16 24 25/* Current versions */ 26#define OCTEON_PCIE_CONSOLE_MAJOR_VERSION 1 27#define OCTEON_PCIE_CONSOLE_MINOR_VERSION 0 28 29#define OCTEON_PCIE_CONSOLE_BLOCK_NAME "__pci_console" 30 31/* 32 * Structure that defines a single console. 33 * Note: when read_index == write_index, the buffer is empty. 34 * The actual usable size of each console is console_buf_size -1; 35 */ 36struct octeon_pcie_console { 37 u64 input_base_addr; 38 u32 input_read_index; 39 u32 input_write_index; 40 u64 output_base_addr; 41 u32 output_read_index; 42 u32 output_write_index; 43 u32 lock; 44 u32 buf_size; 45}; 46 47/* 48 * This is the main container structure that contains all the information 49 * about all PCI consoles. The address of this structure is passed to various 50 * routines that operation on PCI consoles. 51 */ 52struct octeon_pcie_console_desc { 53 u32 major_version; 54 u32 minor_version; 55 u32 lock; 56 u32 flags; 57 u32 num_consoles; 58 u32 pad; 59 /* must be 64 bit aligned here... */ 60 /* Array of addresses of octeon_pcie_console_t structures */ 61 u64 console_addr_array[0]; 62 /* Implicit storage for console_addr_array */ 63}; 64 65struct octeon_pcie_console_priv { 66 struct octeon_pcie_console *console; 67 int console_num; 68 bool console_active; 69}; 70 71/* Flag definitions for read/write functions */ 72enum { 73 /* 74 * If set, read/write functions won't block waiting for space or data. 75 * For reads, 0 bytes may be read, and for writes not all of the 76 * supplied data may be written. 77 */ 78 OCT_PCI_CON_FLAG_NONBLOCK = 1 << 0, 79}; 80 81static int buffer_free_bytes(u32 buffer_size, u32 wr_idx, u32 rd_idx) 82{ 83 if (rd_idx >= buffer_size || wr_idx >= buffer_size) 84 return -1; 85 86 return ((buffer_size - 1) - (wr_idx - rd_idx)) % buffer_size; 87} 88 89static int buffer_avail_bytes(u32 buffer_size, u32 wr_idx, u32 rd_idx) 90{ 91 if (rd_idx >= buffer_size || wr_idx >= buffer_size) 92 return -1; 93 94 return buffer_size - 1 - buffer_free_bytes(buffer_size, wr_idx, rd_idx); 95} 96 97static int buffer_read_avail(struct udevice *dev, unsigned int console_num) 98{ 99 struct octeon_pcie_console_priv *priv = dev_get_priv(dev); 100 struct octeon_pcie_console *cons_ptr = priv->console; 101 int avail; 102 103 avail = buffer_avail_bytes(cons_ptr->buf_size, 104 cons_ptr->input_write_index, 105 cons_ptr->input_read_index); 106 if (avail >= 0) 107 return avail; 108 109 return 0; 110} 111 112static int octeon_pcie_console_read(struct udevice *dev, 113 unsigned int console_num, char *buffer, 114 int buffer_size, u32 flags) 115{ 116 struct octeon_pcie_console_priv *priv = dev_get_priv(dev); 117 struct octeon_pcie_console *cons_ptr = priv->console; 118 int avail; 119 char *buf_ptr; 120 int bytes_read; 121 int read_size; 122 123 buf_ptr = (char *)cvmx_phys_to_ptr(cons_ptr->input_base_addr); 124 125 avail = buffer_avail_bytes(cons_ptr->buf_size, 126 cons_ptr->input_write_index, 127 cons_ptr->input_read_index); 128 if (avail < 0) 129 return avail; 130 131 if (!(flags & OCT_PCI_CON_FLAG_NONBLOCK)) { 132 /* Wait for some data to be available */ 133 while (0 == (avail = buffer_avail_bytes(cons_ptr->buf_size, 134 cons_ptr->input_write_index, 135 cons_ptr->input_read_index))) { 136 mdelay(10); 137 schedule(); 138 } 139 } 140 141 bytes_read = 0; 142 143 /* Don't overflow the buffer passed to us */ 144 read_size = min_t(int, avail, buffer_size); 145 146 /* Limit ourselves to what we can input in a contiguous block */ 147 if (cons_ptr->input_read_index + read_size >= cons_ptr->buf_size) 148 read_size = cons_ptr->buf_size - cons_ptr->input_read_index; 149 150 memcpy(buffer, buf_ptr + cons_ptr->input_read_index, read_size); 151 cons_ptr->input_read_index = 152 (cons_ptr->input_read_index + read_size) % cons_ptr->buf_size; 153 bytes_read += read_size; 154 155 /* Mark the PCIe console to be active from now on */ 156 if (bytes_read) 157 priv->console_active = true; 158 159 return bytes_read; 160} 161 162static int octeon_pcie_console_write(struct udevice *dev, 163 unsigned int console_num, 164 const char *buffer, 165 int bytes_to_write, u32 flags) 166{ 167 struct octeon_pcie_console_priv *priv = dev_get_priv(dev); 168 struct octeon_pcie_console *cons_ptr = priv->console; 169 int avail; 170 char *buf_ptr; 171 int bytes_written; 172 173 buf_ptr = (char *)cvmx_phys_to_ptr(cons_ptr->output_base_addr); 174 bytes_written = 0; 175 while (bytes_to_write > 0) { 176 avail = buffer_free_bytes(cons_ptr->buf_size, 177 cons_ptr->output_write_index, 178 cons_ptr->output_read_index); 179 180 if (avail > 0) { 181 int write_size = min_t(int, avail, bytes_to_write); 182 183 /* 184 * Limit ourselves to what we can output in a contiguous 185 * block 186 */ 187 if (cons_ptr->output_write_index + write_size >= 188 cons_ptr->buf_size) { 189 write_size = cons_ptr->buf_size - 190 cons_ptr->output_write_index; 191 } 192 193 memcpy(buf_ptr + cons_ptr->output_write_index, 194 buffer + bytes_written, write_size); 195 /* 196 * Make sure data is visible before changing write 197 * index 198 */ 199 CVMX_SYNCW; 200 cons_ptr->output_write_index = 201 (cons_ptr->output_write_index + write_size) % 202 cons_ptr->buf_size; 203 bytes_to_write -= write_size; 204 bytes_written += write_size; 205 } else if (avail == 0) { 206 /* 207 * Check to see if we should wait for room, or return 208 * after a partial write 209 */ 210 if (flags & OCT_PCI_CON_FLAG_NONBLOCK) 211 goto done; 212 213 schedule(); 214 mdelay(10); /* Delay if we are spinning */ 215 } else { 216 bytes_written = -1; 217 goto done; 218 } 219 } 220 221done: 222 return bytes_written; 223} 224 225static struct octeon_pcie_console_desc *octeon_pcie_console_init(int num_consoles, 226 int buffer_size) 227{ 228 struct octeon_pcie_console_desc *cons_desc_ptr; 229 struct octeon_pcie_console *cons_ptr; 230 s64 addr; 231 u64 avail_addr; 232 int alloc_size; 233 int i; 234 235 /* Compute size required for pci console structure */ 236 alloc_size = num_consoles * 237 (buffer_size * 2 + sizeof(struct octeon_pcie_console) + 238 sizeof(u64)) + sizeof(struct octeon_pcie_console_desc); 239 240 /* 241 * Allocate memory for the consoles. This must be in the range 242 * addresssible by the bootloader. 243 * Try to do so in a manner which minimizes fragmentation. We try to 244 * put it at the top of DDR0 or bottom of DDR2 first, and only do 245 * generic allocation if those fail 246 */ 247 addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, 248 OCTEON_DDR0_SIZE - alloc_size - 128, 249 OCTEON_DDR0_SIZE, 128, 250 OCTEON_PCIE_CONSOLE_BLOCK_NAME, 251 CVMX_BOOTMEM_FLAG_END_ALLOC); 252 if (addr < 0) { 253 addr = cvmx_bootmem_phy_named_block_alloc(alloc_size, 0, 254 0x1fffffff, 128, 255 OCTEON_PCIE_CONSOLE_BLOCK_NAME, 256 CVMX_BOOTMEM_FLAG_END_ALLOC); 257 } 258 if (addr < 0) 259 return 0; 260 261 cons_desc_ptr = cvmx_phys_to_ptr(addr); 262 263 /* Clear entire alloc'ed memory */ 264 memset(cons_desc_ptr, 0, alloc_size); 265 266 /* Initialize as locked until we are done */ 267 cons_desc_ptr->lock = 1; 268 CVMX_SYNCW; 269 cons_desc_ptr->num_consoles = num_consoles; 270 cons_desc_ptr->flags = 0; 271 cons_desc_ptr->major_version = OCTEON_PCIE_CONSOLE_MAJOR_VERSION; 272 cons_desc_ptr->minor_version = OCTEON_PCIE_CONSOLE_MINOR_VERSION; 273 274 avail_addr = addr + sizeof(struct octeon_pcie_console_desc) + 275 num_consoles * sizeof(u64); 276 277 for (i = 0; i < num_consoles; i++) { 278 cons_desc_ptr->console_addr_array[i] = avail_addr; 279 cons_ptr = (void *)cons_desc_ptr->console_addr_array[i]; 280 avail_addr += sizeof(struct octeon_pcie_console); 281 cons_ptr->input_base_addr = avail_addr; 282 avail_addr += buffer_size; 283 cons_ptr->output_base_addr = avail_addr; 284 avail_addr += buffer_size; 285 cons_ptr->buf_size = buffer_size; 286 } 287 CVMX_SYNCW; 288 cons_desc_ptr->lock = 0; 289 290 return cvmx_phys_to_ptr(addr); 291} 292 293static int octeon_pcie_console_getc(struct udevice *dev) 294{ 295 char c; 296 297 octeon_pcie_console_read(dev, 0, &c, 1, 0); 298 return c; 299} 300 301static int octeon_pcie_console_putc(struct udevice *dev, const char c) 302{ 303 struct octeon_pcie_console_priv *priv = dev_get_priv(dev); 304 305 if (priv->console_active) 306 octeon_pcie_console_write(dev, 0, (char *)&c, 1, 0); 307 308 return 0; 309} 310 311static int octeon_pcie_console_pending(struct udevice *dev, bool input) 312{ 313 if (input) { 314 udelay(100); 315 return buffer_read_avail(dev, 0) > 0; 316 } 317 318 return 0; 319} 320 321static const struct dm_serial_ops octeon_pcie_console_ops = { 322 .getc = octeon_pcie_console_getc, 323 .putc = octeon_pcie_console_putc, 324 .pending = octeon_pcie_console_pending, 325}; 326 327static int octeon_pcie_console_probe(struct udevice *dev) 328{ 329 struct octeon_pcie_console_priv *priv = dev_get_priv(dev); 330 struct octeon_pcie_console_desc *cons_desc; 331 int console_count; 332 int console_size; 333 int console_num; 334 335 /* 336 * Currently only 1 console is supported. Perhaps we need to add 337 * a console nexus if more than one needs to be supported. 338 */ 339 console_count = 1; 340 console_size = 1024; 341 console_num = 0; 342 343 cons_desc = octeon_pcie_console_init(console_count, console_size); 344 priv->console = 345 cvmx_phys_to_ptr(cons_desc->console_addr_array[console_num]); 346 347 debug("PCI console init succeeded, %d consoles, %d bytes each\n", 348 console_count, console_size); 349 350 return 0; 351} 352 353static const struct udevice_id octeon_pcie_console_serial_id[] = { 354 { .compatible = "marvell,pci-console", }, 355 { }, 356}; 357 358U_BOOT_DRIVER(octeon_pcie_console) = { 359 .name = DRIVER_NAME, 360 .id = UCLASS_SERIAL, 361 .ops = &octeon_pcie_console_ops, 362 .of_match = of_match_ptr(octeon_pcie_console_serial_id), 363 .probe = octeon_pcie_console_probe, 364 .priv_auto = sizeof(struct octeon_pcie_console_priv), 365}; 366