1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2018-2020 Broadcom.
4 */
5
6#include <linux/tty.h>
7#include <linux/tty_driver.h>
8#include <linux/tty_flip.h>
9
10#include "bcm_vk.h"
11
12/* TTYVK base offset is 0x30000 into BAR1 */
13#define BAR1_TTYVK_BASE_OFFSET	0x300000
14/* Each TTYVK channel (TO or FROM) is 0x10000 */
15#define BAR1_TTYVK_CHAN_OFFSET	0x100000
16/* Each TTYVK channel has TO and FROM, hence the * 2 */
17#define BAR1_TTYVK_BASE(index)	(BAR1_TTYVK_BASE_OFFSET + \
18				 ((index) * BAR1_TTYVK_CHAN_OFFSET * 2))
19/* TO TTYVK channel base comes before FROM for each index */
20#define TO_TTYK_BASE(index)	BAR1_TTYVK_BASE(index)
21#define FROM_TTYK_BASE(index)	(BAR1_TTYVK_BASE(index) + \
22				 BAR1_TTYVK_CHAN_OFFSET)
23
24struct bcm_vk_tty_chan {
25	u32 reserved;
26	u32 size;
27	u32 wr;
28	u32 rd;
29	u32 *data;
30};
31
32#define VK_BAR_CHAN(v, DIR, e)	((v)->DIR##_offset \
33				 + offsetof(struct bcm_vk_tty_chan, e))
34#define VK_BAR_CHAN_SIZE(v, DIR)	VK_BAR_CHAN(v, DIR, size)
35#define VK_BAR_CHAN_WR(v, DIR)		VK_BAR_CHAN(v, DIR, wr)
36#define VK_BAR_CHAN_RD(v, DIR)		VK_BAR_CHAN(v, DIR, rd)
37#define VK_BAR_CHAN_DATA(v, DIR, off)	(VK_BAR_CHAN(v, DIR, data) + (off))
38
39#define VK_BAR0_REGSEG_TTY_DB_OFFSET	0x86c
40
41/* Poll every 1/10 of second - temp hack till we use MSI interrupt */
42#define SERIAL_TIMER_VALUE (HZ / 10)
43
44static void bcm_vk_tty_poll(struct timer_list *t)
45{
46	struct bcm_vk *vk = from_timer(vk, t, serial_timer);
47
48	queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
49	mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
50}
51
52irqreturn_t bcm_vk_tty_irqhandler(int irq, void *dev_id)
53{
54	struct bcm_vk *vk = dev_id;
55
56	queue_work(vk->tty_wq_thread, &vk->tty_wq_work);
57
58	return IRQ_HANDLED;
59}
60
61static void bcm_vk_tty_wq_handler(struct work_struct *work)
62{
63	struct bcm_vk *vk = container_of(work, struct bcm_vk, tty_wq_work);
64	struct bcm_vk_tty *vktty;
65	int card_status;
66	int count;
67	int i;
68	int wr;
69	u8 c;
70
71	card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
72	if (BCM_VK_INTF_IS_DOWN(card_status))
73		return;
74
75	for (i = 0; i < BCM_VK_NUM_TTY; i++) {
76		count = 0;
77		/* Check the card status that the tty channel is ready */
78		if ((card_status & BIT(i)) == 0)
79			continue;
80
81		vktty = &vk->tty[i];
82
83		/* Don't increment read index if tty app is closed */
84		if (!vktty->is_opened)
85			continue;
86
87		/* Fetch the wr offset in buffer from VK */
88		wr = vkread32(vk, BAR_1, VK_BAR_CHAN_WR(vktty, from));
89
90		/* safe to ignore until bar read gives proper size */
91		if (vktty->from_size == 0)
92			continue;
93
94		if (wr >= vktty->from_size) {
95			dev_err(&vk->pdev->dev,
96				"ERROR: wq handler ttyVK%d wr:0x%x > 0x%x\n",
97				i, wr, vktty->from_size);
98			/* Need to signal and close device in this case */
99			continue;
100		}
101
102		/*
103		 * Simple read of circular buffer and
104		 * insert into tty flip buffer
105		 */
106		while (vk->tty[i].rd != wr) {
107			c = vkread8(vk, BAR_1,
108				    VK_BAR_CHAN_DATA(vktty, from, vktty->rd));
109			vktty->rd++;
110			if (vktty->rd >= vktty->from_size)
111				vktty->rd = 0;
112			tty_insert_flip_char(&vktty->port, c, TTY_NORMAL);
113			count++;
114		}
115
116		if (count) {
117			tty_flip_buffer_push(&vktty->port);
118
119			/* Update read offset from shadow register to card */
120			vkwrite32(vk, vktty->rd, BAR_1,
121				  VK_BAR_CHAN_RD(vktty, from));
122		}
123	}
124}
125
126static int bcm_vk_tty_open(struct tty_struct *tty, struct file *file)
127{
128	int card_status;
129	struct bcm_vk *vk;
130	struct bcm_vk_tty *vktty;
131	int index;
132
133	/* initialize the pointer in case something fails */
134	tty->driver_data = NULL;
135
136	vk = (struct bcm_vk *)dev_get_drvdata(tty->dev);
137	index = tty->index;
138
139	if (index >= BCM_VK_NUM_TTY)
140		return -EINVAL;
141
142	vktty = &vk->tty[index];
143
144	vktty->pid = task_pid_nr(current);
145	vktty->to_offset = TO_TTYK_BASE(index);
146	vktty->from_offset = FROM_TTYK_BASE(index);
147
148	/* Do not allow tty device to be opened if tty on card not ready */
149	card_status = vkread32(vk, BAR_0, BAR_CARD_STATUS);
150	if (BCM_VK_INTF_IS_DOWN(card_status) || ((card_status & BIT(index)) == 0))
151		return -EBUSY;
152
153	/*
154	 * Get shadow registers of the buffer sizes and the "to" write offset
155	 * and "from" read offset
156	 */
157	vktty->to_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, to));
158	vktty->wr = vkread32(vk, BAR_1,  VK_BAR_CHAN_WR(vktty, to));
159	vktty->from_size = vkread32(vk, BAR_1, VK_BAR_CHAN_SIZE(vktty, from));
160	vktty->rd = vkread32(vk, BAR_1,  VK_BAR_CHAN_RD(vktty, from));
161	vktty->is_opened = true;
162
163	if (tty->count == 1 && !vktty->irq_enabled) {
164		timer_setup(&vk->serial_timer, bcm_vk_tty_poll, 0);
165		mod_timer(&vk->serial_timer, jiffies + SERIAL_TIMER_VALUE);
166	}
167	return 0;
168}
169
170static void bcm_vk_tty_close(struct tty_struct *tty, struct file *file)
171{
172	struct bcm_vk *vk = dev_get_drvdata(tty->dev);
173
174	if (tty->index >= BCM_VK_NUM_TTY)
175		return;
176
177	vk->tty[tty->index].is_opened = false;
178
179	if (tty->count == 1)
180		del_timer_sync(&vk->serial_timer);
181}
182
183static void bcm_vk_tty_doorbell(struct bcm_vk *vk, u32 db_val)
184{
185	vkwrite32(vk, db_val, BAR_0,
186		  VK_BAR0_REGSEG_DB_BASE + VK_BAR0_REGSEG_TTY_DB_OFFSET);
187}
188
189static ssize_t bcm_vk_tty_write(struct tty_struct *tty, const u8 *buffer,
190				size_t count)
191{
192	int index;
193	struct bcm_vk *vk;
194	struct bcm_vk_tty *vktty;
195	size_t i;
196
197	index = tty->index;
198	vk = dev_get_drvdata(tty->dev);
199	vktty = &vk->tty[index];
200
201	/* Simple write each byte to circular buffer */
202	for (i = 0; i < count; i++) {
203		vkwrite8(vk, buffer[i], BAR_1,
204			 VK_BAR_CHAN_DATA(vktty, to, vktty->wr));
205		vktty->wr++;
206		if (vktty->wr >= vktty->to_size)
207			vktty->wr = 0;
208	}
209	/* Update write offset from shadow register to card */
210	vkwrite32(vk, vktty->wr, BAR_1, VK_BAR_CHAN_WR(vktty, to));
211	bcm_vk_tty_doorbell(vk, 0);
212
213	return count;
214}
215
216static unsigned int bcm_vk_tty_write_room(struct tty_struct *tty)
217{
218	struct bcm_vk *vk = dev_get_drvdata(tty->dev);
219
220	return vk->tty[tty->index].to_size - 1;
221}
222
223static const struct tty_operations serial_ops = {
224	.open = bcm_vk_tty_open,
225	.close = bcm_vk_tty_close,
226	.write = bcm_vk_tty_write,
227	.write_room = bcm_vk_tty_write_room,
228};
229
230int bcm_vk_tty_init(struct bcm_vk *vk, char *name)
231{
232	int i;
233	int err;
234	struct tty_driver *tty_drv;
235	struct device *dev = &vk->pdev->dev;
236
237	tty_drv = tty_alloc_driver
238				(BCM_VK_NUM_TTY,
239				 TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV);
240	if (IS_ERR(tty_drv))
241		return PTR_ERR(tty_drv);
242
243	/* Save struct tty_driver for uninstalling the device */
244	vk->tty_drv = tty_drv;
245
246	/* initialize the tty driver */
247	tty_drv->driver_name = KBUILD_MODNAME;
248	tty_drv->name = kstrdup(name, GFP_KERNEL);
249	if (!tty_drv->name) {
250		err = -ENOMEM;
251		goto err_tty_driver_kref_put;
252	}
253	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
254	tty_drv->subtype = SERIAL_TYPE_NORMAL;
255	tty_drv->init_termios = tty_std_termios;
256	tty_set_operations(tty_drv, &serial_ops);
257
258	/* register the tty driver */
259	err = tty_register_driver(tty_drv);
260	if (err) {
261		dev_err(dev, "tty_register_driver failed\n");
262		goto err_kfree_tty_name;
263	}
264
265	for (i = 0; i < BCM_VK_NUM_TTY; i++) {
266		struct device *tty_dev;
267
268		tty_port_init(&vk->tty[i].port);
269		tty_dev = tty_port_register_device_attr(&vk->tty[i].port,
270							tty_drv, i, dev, vk,
271							NULL);
272		if (IS_ERR(tty_dev)) {
273			err = PTR_ERR(tty_dev);
274			goto unwind;
275		}
276		vk->tty[i].is_opened = false;
277	}
278
279	INIT_WORK(&vk->tty_wq_work, bcm_vk_tty_wq_handler);
280	vk->tty_wq_thread = create_singlethread_workqueue("tty");
281	if (!vk->tty_wq_thread) {
282		dev_err(dev, "Fail to create tty workqueue thread\n");
283		err = -ENOMEM;
284		goto unwind;
285	}
286	return 0;
287
288unwind:
289	while (--i >= 0)
290		tty_port_unregister_device(&vk->tty[i].port, tty_drv, i);
291	tty_unregister_driver(tty_drv);
292
293err_kfree_tty_name:
294	kfree(tty_drv->name);
295	tty_drv->name = NULL;
296
297err_tty_driver_kref_put:
298	tty_driver_kref_put(tty_drv);
299
300	return err;
301}
302
303void bcm_vk_tty_exit(struct bcm_vk *vk)
304{
305	int i;
306
307	del_timer_sync(&vk->serial_timer);
308	for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
309		tty_port_unregister_device(&vk->tty[i].port,
310					   vk->tty_drv,
311					   i);
312		tty_port_destroy(&vk->tty[i].port);
313	}
314	tty_unregister_driver(vk->tty_drv);
315
316	kfree(vk->tty_drv->name);
317	vk->tty_drv->name = NULL;
318
319	tty_driver_kref_put(vk->tty_drv);
320}
321
322void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk)
323{
324	struct bcm_vk_tty *vktty;
325	int i;
326
327	for (i = 0; i < BCM_VK_NUM_TTY; ++i) {
328		vktty = &vk->tty[i];
329		if (vktty->pid)
330			kill_pid(find_vpid(vktty->pid), SIGKILL, 1);
331	}
332}
333
334void bcm_vk_tty_wq_exit(struct bcm_vk *vk)
335{
336	cancel_work_sync(&vk->tty_wq_work);
337	destroy_workqueue(vk->tty_wq_thread);
338}
339