summaryrefslogtreecommitdiffstats
path: root/target/linux/bcm27xx/patches-6.1/950-0877-serial-pl011-rp1-uart-support.patch
blob: b0b9897e897d253a7fe5f84f34e0a741a281292b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
From f88da9e21d8eff58eeb9280ae96bf9593121d8eb Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.com>
Date: Wed, 12 Oct 2022 13:24:51 +0100
Subject: [PATCH] serial: pl011: rp1 uart support

Signed-off-by: Phil Elwell <phil@raspberrypi.com>
---
 drivers/tty/serial/amba-pl011.c | 96 +++++++++++++++++++++++++++++++++
 1 file changed, 96 insertions(+)

--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -152,6 +152,20 @@ static const struct vendor_data vendor_s
 	.fixed_options		= true,
 };
 
+static struct vendor_data vendor_arm_axi = {
+	.reg_offset		= pl011_std_offsets,
+	.ifls			= UART011_IFLS_RX4_8 | UART011_IFLS_TX4_8,
+	.fr_busy		= UART01x_FR_BUSY,
+	.fr_dsr			= UART01x_FR_DSR,
+	.fr_cts			= UART01x_FR_CTS,
+	.fr_ri			= UART011_FR_RI,
+	.oversampling		= false,
+	.dma_threshold		= false,
+	.cts_event_workaround	= false,
+	.always_enabled		= false,
+	.fixed_options		= false,
+};
+
 #ifdef CONFIG_ACPI_SPCR_TABLE
 static const struct vendor_data vendor_qdt_qdf2400_e44 = {
 	.reg_offset		= pl011_std_offsets,
@@ -2972,6 +2986,86 @@ static struct platform_driver arm_sbsa_u
 	},
 };
 
+static int pl011_axi_probe(struct platform_device *pdev)
+{
+	struct uart_amba_port *uap;
+	struct vendor_data *vendor =  &vendor_arm_axi;
+	struct resource *r;
+	unsigned int periphid;
+	int portnr, ret, irq;
+
+	portnr = pl011_find_free_port();
+	if (portnr < 0)
+		return portnr;
+
+	uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port),
+			   GFP_KERNEL);
+	if (!uap)
+		return -ENOMEM;
+
+	uap->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(uap->clk))
+		return PTR_ERR(uap->clk);
+
+	if (of_property_read_bool(pdev->dev.of_node, "cts-event-workaround")) {
+		vendor->cts_event_workaround = true;
+		dev_info(&pdev->dev, "cts_event_workaround enabled\n");
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	periphid = 0x00241011; /* A safe default */
+	of_property_read_u32(pdev->dev.of_node, "arm,primecell-periphid",
+			     &periphid);
+
+	uap->reg_offset = vendor->reg_offset;
+	uap->vendor = vendor;
+	uap->fifosize = (AMBA_REV_BITS(periphid) < 3) ? 16 : 32;
+	uap->port.iotype = vendor->access_32b ? UPIO_MEM32 : UPIO_MEM;
+	uap->port.irq = irq;
+	uap->port.ops = &amba_pl011_pops;
+
+	snprintf(uap->type, sizeof(uap->type), "PL011 AXI");
+
+	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	ret = pl011_setup_port(&pdev->dev, uap, r, portnr);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, uap);
+
+	return pl011_register_port(uap);
+}
+
+static int pl011_axi_remove(struct platform_device *pdev)
+{
+	struct uart_amba_port *uap = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&amba_reg, &uap->port);
+	pl011_unregister_port(uap);
+	return 0;
+}
+
+static const struct of_device_id pl011_axi_of_match[] = {
+	{ .compatible = "arm,pl011-axi" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, pl011_axi_of_match);
+
+static struct platform_driver pl011_axi_platform_driver = {
+	.probe		= pl011_axi_probe,
+	.remove		= pl011_axi_remove,
+	.driver	= {
+		.name	= "pl011-axi",
+		.pm	= &pl011_dev_pm_ops,
+		.of_match_table = of_match_ptr(pl011_axi_of_match),
+		.suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011),
+	},
+};
+
 static const struct amba_id pl011_ids[] = {
 	{
 		.id	= 0x00041011,
@@ -3005,6 +3099,8 @@ static int __init pl011_init(void)
 
 	if (platform_driver_register(&arm_sbsa_uart_platform_driver))
 		pr_warn("could not register SBSA UART platform driver\n");
+	if (platform_driver_register(&pl011_axi_platform_driver))
+		pr_warn("could not register PL011 AXI platform driver\n");
 	return amba_driver_register(&pl011_driver);
 }