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
130
131
132
133
134
135
|
// SPDX-License-Identifier: GPL-2.0+
/*
* Actions Semi OWL SoCs UART driver
*
* Copyright (C) 2015 Actions Semi Co., Ltd.
* Copyright (C) 2018 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
*/
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <errno.h>
#include <fdtdec.h>
#include <serial.h>
#include <asm/io.h>
#include <asm/types.h>
/* UART Registers */
#define OWL_UART_CTL (0x0000)
#define OWL_UART_RXDAT (0x0004)
#define OWL_UART_TXDAT (0x0008)
#define OWL_UART_STAT (0x000C)
/* UART_CTL Register Definitions */
#define OWL_UART_CTL_PRS_NONE GENMASK(6, 4)
#define OWL_UART_CTL_STPS BIT(2)
#define OWL_UART_CTL_DWLS 3
/* UART_STAT Register Definitions */
#define OWL_UART_STAT_TFES BIT(10) /* TX FIFO Empty Status */
#define OWL_UART_STAT_RFFS BIT(9) /* RX FIFO full Status */
#define OWL_UART_STAT_TFFU BIT(6) /* TX FIFO full Status */
#define OWL_UART_STAT_RFEM BIT(5) /* RX FIFO Empty Status */
struct owl_serial_priv {
phys_addr_t base;
};
int owl_serial_setbrg(struct udevice *dev, int baudrate)
{
/* Driver supports only fixed baudrate */
return 0;
}
static int owl_serial_getc(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_RFEM)
return -EAGAIN;
return (int)(readl(priv->base + OWL_UART_RXDAT));
}
static int owl_serial_putc(struct udevice *dev, const char ch)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
if (readl(priv->base + OWL_UART_STAT) & OWL_UART_STAT_TFFU)
return -EAGAIN;
writel(ch, priv->base + OWL_UART_TXDAT);
return 0;
}
static int owl_serial_pending(struct udevice *dev, bool input)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
unsigned int stat = readl(priv->base + OWL_UART_STAT);
if (input)
return !(stat & OWL_UART_STAT_RFEM);
else
return !(stat & OWL_UART_STAT_TFES);
}
static int owl_serial_probe(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
struct clk clk;
u32 uart_ctl;
int ret;
/* Set data, parity and stop bits */
uart_ctl = readl(priv->base + OWL_UART_CTL);
uart_ctl &= ~(OWL_UART_CTL_PRS_NONE);
uart_ctl &= ~(OWL_UART_CTL_STPS);
uart_ctl |= OWL_UART_CTL_DWLS;
writel(uart_ctl, priv->base + OWL_UART_CTL);
/* Enable UART clock */
ret = clk_get_by_index(dev, 0, &clk);
if (ret < 0)
return ret;
ret = clk_enable(&clk);
if (ret < 0)
return ret;
return 0;
}
static int owl_serial_ofdata_to_platdata(struct udevice *dev)
{
struct owl_serial_priv *priv = dev_get_priv(dev);
priv->base = dev_read_addr(dev);
if (priv->base == FDT_ADDR_T_NONE)
return -EINVAL;
return 0;
}
static const struct dm_serial_ops owl_serial_ops = {
.putc = owl_serial_putc,
.pending = owl_serial_pending,
.getc = owl_serial_getc,
.setbrg = owl_serial_setbrg,
};
static const struct udevice_id owl_serial_ids[] = {
{ .compatible = "actions,owl-uart" },
{ }
};
U_BOOT_DRIVER(serial_owl) = {
.name = "serial_owl",
.id = UCLASS_SERIAL,
.of_match = owl_serial_ids,
.ofdata_to_platdata = owl_serial_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct owl_serial_priv),
.probe = owl_serial_probe,
.ops = &owl_serial_ops,
};
|