tegra-tcu.c (7311B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. 4 */ 5 6#include <linux/console.h> 7#include <linux/mailbox_client.h> 8#include <linux/module.h> 9#include <linux/of.h> 10#include <linux/of_device.h> 11#include <linux/platform_device.h> 12#include <linux/serial.h> 13#include <linux/serial_core.h> 14#include <linux/slab.h> 15#include <linux/tty.h> 16#include <linux/tty_flip.h> 17 18#define TCU_MBOX_BYTE(i, x) ((x) << (i * 8)) 19#define TCU_MBOX_BYTE_V(x, i) (((x) >> (i * 8)) & 0xff) 20#define TCU_MBOX_NUM_BYTES(x) ((x) << 24) 21#define TCU_MBOX_NUM_BYTES_V(x) (((x) >> 24) & 0x3) 22 23struct tegra_tcu { 24 struct uart_driver driver; 25#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 26 struct console console; 27#endif 28 struct uart_port port; 29 30 struct mbox_client tx_client, rx_client; 31 struct mbox_chan *tx, *rx; 32}; 33 34static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port) 35{ 36 return TIOCSER_TEMT; 37} 38 39static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) 40{ 41} 42 43static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port) 44{ 45 return 0; 46} 47 48static void tegra_tcu_uart_stop_tx(struct uart_port *port) 49{ 50} 51 52static void tegra_tcu_write_one(struct tegra_tcu *tcu, u32 value, 53 unsigned int count) 54{ 55 void *msg; 56 57 value |= TCU_MBOX_NUM_BYTES(count); 58 msg = (void *)(unsigned long)value; 59 mbox_send_message(tcu->tx, msg); 60 mbox_flush(tcu->tx, 1000); 61} 62 63static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s, 64 unsigned int count) 65{ 66 unsigned int written = 0, i = 0; 67 bool insert_nl = false; 68 u32 value = 0; 69 70 while (i < count) { 71 if (insert_nl) { 72 value |= TCU_MBOX_BYTE(written++, '\n'); 73 insert_nl = false; 74 i++; 75 } else if (s[i] == '\n') { 76 value |= TCU_MBOX_BYTE(written++, '\r'); 77 insert_nl = true; 78 } else { 79 value |= TCU_MBOX_BYTE(written++, s[i++]); 80 } 81 82 if (written == 3) { 83 tegra_tcu_write_one(tcu, value, 3); 84 value = written = 0; 85 } 86 } 87 88 if (written) 89 tegra_tcu_write_one(tcu, value, written); 90} 91 92static void tegra_tcu_uart_start_tx(struct uart_port *port) 93{ 94 struct tegra_tcu *tcu = port->private_data; 95 struct circ_buf *xmit = &port->state->xmit; 96 unsigned long count; 97 98 for (;;) { 99 count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); 100 if (!count) 101 break; 102 103 tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count); 104 xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); 105 } 106 107 uart_write_wakeup(port); 108} 109 110static void tegra_tcu_uart_stop_rx(struct uart_port *port) 111{ 112} 113 114static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl) 115{ 116} 117 118static int tegra_tcu_uart_startup(struct uart_port *port) 119{ 120 return 0; 121} 122 123static void tegra_tcu_uart_shutdown(struct uart_port *port) 124{ 125} 126 127static void tegra_tcu_uart_set_termios(struct uart_port *port, 128 struct ktermios *new, 129 struct ktermios *old) 130{ 131} 132 133static const struct uart_ops tegra_tcu_uart_ops = { 134 .tx_empty = tegra_tcu_uart_tx_empty, 135 .set_mctrl = tegra_tcu_uart_set_mctrl, 136 .get_mctrl = tegra_tcu_uart_get_mctrl, 137 .stop_tx = tegra_tcu_uart_stop_tx, 138 .start_tx = tegra_tcu_uart_start_tx, 139 .stop_rx = tegra_tcu_uart_stop_rx, 140 .break_ctl = tegra_tcu_uart_break_ctl, 141 .startup = tegra_tcu_uart_startup, 142 .shutdown = tegra_tcu_uart_shutdown, 143 .set_termios = tegra_tcu_uart_set_termios, 144}; 145 146#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 147static void tegra_tcu_console_write(struct console *cons, const char *s, 148 unsigned int count) 149{ 150 struct tegra_tcu *tcu = container_of(cons, struct tegra_tcu, console); 151 152 tegra_tcu_write(tcu, s, count); 153} 154 155static int tegra_tcu_console_setup(struct console *cons, char *options) 156{ 157 return 0; 158} 159#endif 160 161static void tegra_tcu_receive(struct mbox_client *cl, void *msg) 162{ 163 struct tegra_tcu *tcu = container_of(cl, struct tegra_tcu, rx_client); 164 struct tty_port *port = &tcu->port.state->port; 165 u32 value = (u32)(unsigned long)msg; 166 unsigned int num_bytes, i; 167 168 num_bytes = TCU_MBOX_NUM_BYTES_V(value); 169 170 for (i = 0; i < num_bytes; i++) 171 tty_insert_flip_char(port, TCU_MBOX_BYTE_V(value, i), 172 TTY_NORMAL); 173 174 tty_flip_buffer_push(port); 175} 176 177static int tegra_tcu_probe(struct platform_device *pdev) 178{ 179 struct uart_port *port; 180 struct tegra_tcu *tcu; 181 int err; 182 183 tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL); 184 if (!tcu) 185 return -ENOMEM; 186 187 tcu->tx_client.dev = &pdev->dev; 188 tcu->rx_client.dev = &pdev->dev; 189 tcu->rx_client.rx_callback = tegra_tcu_receive; 190 191 tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx"); 192 if (IS_ERR(tcu->tx)) { 193 err = PTR_ERR(tcu->tx); 194 dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err); 195 return err; 196 } 197 198#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 199 /* setup the console */ 200 strcpy(tcu->console.name, "ttyTCU"); 201 tcu->console.device = uart_console_device; 202 tcu->console.flags = CON_PRINTBUFFER | CON_ANYTIME; 203 tcu->console.index = -1; 204 tcu->console.write = tegra_tcu_console_write; 205 tcu->console.setup = tegra_tcu_console_setup; 206 tcu->console.data = &tcu->driver; 207#endif 208 209 /* setup the driver */ 210 tcu->driver.owner = THIS_MODULE; 211 tcu->driver.driver_name = "tegra-tcu"; 212 tcu->driver.dev_name = "ttyTCU"; 213#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 214 tcu->driver.cons = &tcu->console; 215#endif 216 tcu->driver.nr = 1; 217 218 err = uart_register_driver(&tcu->driver); 219 if (err) { 220 dev_err(&pdev->dev, "failed to register UART driver: %d\n", 221 err); 222 goto free_tx; 223 } 224 225 /* setup the port */ 226 port = &tcu->port; 227 spin_lock_init(&port->lock); 228 port->dev = &pdev->dev; 229 port->type = PORT_TEGRA_TCU; 230 port->ops = &tegra_tcu_uart_ops; 231 port->fifosize = 1; 232 port->iotype = UPIO_MEM; 233 port->flags = UPF_BOOT_AUTOCONF; 234 port->private_data = tcu; 235 236 err = uart_add_one_port(&tcu->driver, port); 237 if (err) { 238 dev_err(&pdev->dev, "failed to add UART port: %d\n", err); 239 goto unregister_uart; 240 } 241 242 /* 243 * Request RX channel after creating port to ensure tcu->port 244 * is ready for any immediate incoming bytes. 245 */ 246 tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); 247 if (IS_ERR(tcu->rx)) { 248 err = PTR_ERR(tcu->rx); 249 dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); 250 goto remove_uart_port; 251 } 252 253 platform_set_drvdata(pdev, tcu); 254#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 255 register_console(&tcu->console); 256#endif 257 258 return 0; 259 260remove_uart_port: 261 uart_remove_one_port(&tcu->driver, &tcu->port); 262unregister_uart: 263 uart_unregister_driver(&tcu->driver); 264free_tx: 265 mbox_free_channel(tcu->tx); 266 267 return err; 268} 269 270static int tegra_tcu_remove(struct platform_device *pdev) 271{ 272 struct tegra_tcu *tcu = platform_get_drvdata(pdev); 273 274#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) 275 unregister_console(&tcu->console); 276#endif 277 mbox_free_channel(tcu->rx); 278 uart_remove_one_port(&tcu->driver, &tcu->port); 279 uart_unregister_driver(&tcu->driver); 280 mbox_free_channel(tcu->tx); 281 282 return 0; 283} 284 285static const struct of_device_id tegra_tcu_match[] = { 286 { .compatible = "nvidia,tegra194-tcu" }, 287 { } 288}; 289MODULE_DEVICE_TABLE(of, tegra_tcu_match); 290 291static struct platform_driver tegra_tcu_driver = { 292 .driver = { 293 .name = "tegra-tcu", 294 .of_match_table = tegra_tcu_match, 295 }, 296 .probe = tegra_tcu_probe, 297 .remove = tegra_tcu_remove, 298}; 299module_platform_driver(tegra_tcu_driver); 300 301MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); 302MODULE_LICENSE("GPL v2"); 303MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver");