Linux-libre 3.17.4-gnu
[librecmc/linux-libre.git] / drivers / gpu / drm / sti / sti_vtac.c
1 /*
2  * Copyright (C) STMicroelectronics SA 2014
3  * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4  * License terms:  GNU General Public License (GPL), version 2
5  */
6
7 #include <linux/clk.h>
8 #include <linux/io.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/platform_device.h>
12
13 #include <drm/drmP.h>
14
15 /* registers offset */
16 #define VTAC_CONFIG                     0x00
17 #define VTAC_RX_FIFO_CONFIG             0x04
18 #define VTAC_FIFO_CONFIG_VAL            0x04
19
20 #define VTAC_SYS_CFG8521                0x824
21 #define VTAC_SYS_CFG8522                0x828
22
23 /* Number of phyts per pixel */
24 #define VTAC_2_5_PPP                    0x0005
25 #define VTAC_3_PPP                      0x0006
26 #define VTAC_4_PPP                      0x0008
27 #define VTAC_5_PPP                      0x000A
28 #define VTAC_6_PPP                      0x000C
29 #define VTAC_13_PPP                     0x001A
30 #define VTAC_14_PPP                     0x001C
31 #define VTAC_15_PPP                     0x001E
32 #define VTAC_16_PPP                     0x0020
33 #define VTAC_17_PPP                     0x0022
34 #define VTAC_18_PPP                     0x0024
35
36 /* enable bits */
37 #define VTAC_ENABLE                     0x3003
38
39 #define VTAC_TX_PHY_ENABLE_CLK_PHY      BIT(0)
40 #define VTAC_TX_PHY_ENABLE_CLK_DLL      BIT(1)
41 #define VTAC_TX_PHY_PLL_NOT_OSC_MODE    BIT(3)
42 #define VTAC_TX_PHY_RST_N_DLL_SWITCH    BIT(4)
43 #define VTAC_TX_PHY_PROG_N3             BIT(9)
44
45
46 /**
47  * VTAC mode structure
48  *
49  * @vid_in_width: Video Data Resolution
50  * @phyts_width: Width of phyt buses(phyt low and phyt high).
51  * @phyts_per_pixel: Number of phyts sent per pixel
52  */
53 struct sti_vtac_mode {
54         u32 vid_in_width;
55         u32 phyts_width;
56         u32 phyts_per_pixel;
57 };
58
59 static const struct sti_vtac_mode vtac_mode_main = {0x2, 0x2, VTAC_5_PPP};
60 static const struct sti_vtac_mode vtac_mode_aux = {0x1, 0x0, VTAC_17_PPP};
61
62 /**
63  * VTAC structure
64  *
65  * @dev: pointer to device structure
66  * @regs: ioremapped registers for RX and TX devices
67  * @phy_regs: phy registers for TX device
68  * @clk: clock
69  * @mode: main or auxillary configuration mode
70  */
71 struct sti_vtac {
72         struct device *dev;
73         void __iomem *regs;
74         void __iomem *phy_regs;
75         struct clk *clk;
76         const struct sti_vtac_mode *mode;
77 };
78
79 static void sti_vtac_rx_set_config(struct sti_vtac *vtac)
80 {
81         u32 config;
82
83         /* Enable VTAC clock */
84         if (clk_prepare_enable(vtac->clk))
85                 DRM_ERROR("Failed to prepare/enable vtac_rx clock.\n");
86
87         writel(VTAC_FIFO_CONFIG_VAL, vtac->regs + VTAC_RX_FIFO_CONFIG);
88
89         config = VTAC_ENABLE;
90         config |= vtac->mode->vid_in_width << 4;
91         config |= vtac->mode->phyts_width << 16;
92         config |= vtac->mode->phyts_per_pixel << 23;
93         writel(config, vtac->regs + VTAC_CONFIG);
94 }
95
96 static void sti_vtac_tx_set_config(struct sti_vtac *vtac)
97 {
98         u32 phy_config;
99         u32 config;
100
101         /* Enable VTAC clock */
102         if (clk_prepare_enable(vtac->clk))
103                 DRM_ERROR("Failed to prepare/enable vtac_tx clock.\n");
104
105         /* Configure vtac phy */
106         phy_config = 0x00000000;
107         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8522);
108         phy_config = VTAC_TX_PHY_ENABLE_CLK_PHY;
109         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
110         phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
111         phy_config |= VTAC_TX_PHY_PROG_N3;
112         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
113         phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
114         phy_config |= VTAC_TX_PHY_ENABLE_CLK_DLL;
115         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
116         phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
117         phy_config |= VTAC_TX_PHY_RST_N_DLL_SWITCH;
118         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
119         phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
120         phy_config |= VTAC_TX_PHY_PLL_NOT_OSC_MODE;
121         writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
122
123         /* Configure vtac tx */
124         config = VTAC_ENABLE;
125         config |= vtac->mode->vid_in_width << 4;
126         config |= vtac->mode->phyts_width << 16;
127         config |= vtac->mode->phyts_per_pixel << 23;
128         writel(config, vtac->regs + VTAC_CONFIG);
129 }
130
131 static const struct of_device_id vtac_of_match[] = {
132         {
133                 .compatible = "st,vtac-main",
134                 .data = &vtac_mode_main,
135         }, {
136                 .compatible = "st,vtac-aux",
137                 .data = &vtac_mode_aux,
138         }, {
139                 /* end node */
140         }
141 };
142 MODULE_DEVICE_TABLE(of, vtac_of_match);
143
144 static int sti_vtac_probe(struct platform_device *pdev)
145 {
146         struct device *dev = &pdev->dev;
147         struct device_node *np = dev->of_node;
148         const struct of_device_id *id;
149         struct sti_vtac *vtac;
150         struct resource *res;
151
152         vtac = devm_kzalloc(dev, sizeof(*vtac), GFP_KERNEL);
153         if (!vtac)
154                 return -ENOMEM;
155
156         vtac->dev = dev;
157
158         id = of_match_node(vtac_of_match, np);
159         if (!id)
160                 return -ENOMEM;
161
162         vtac->mode = id->data;
163
164         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
165         if (!res) {
166                 DRM_ERROR("Invalid resource\n");
167                 return -ENOMEM;
168         }
169         vtac->regs = devm_ioremap_resource(dev, res);
170         if (IS_ERR(vtac->regs))
171                 return PTR_ERR(vtac->regs);
172
173
174         vtac->clk = devm_clk_get(dev, "vtac");
175         if (IS_ERR(vtac->clk)) {
176                 DRM_ERROR("Cannot get vtac clock\n");
177                 return PTR_ERR(vtac->clk);
178         }
179
180         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
181         if (res) {
182                 vtac->phy_regs = devm_ioremap_nocache(dev, res->start,
183                                                  resource_size(res));
184                 sti_vtac_tx_set_config(vtac);
185         } else {
186
187                 sti_vtac_rx_set_config(vtac);
188         }
189
190         platform_set_drvdata(pdev, vtac);
191         DRM_INFO("%s %s\n", __func__, dev_name(vtac->dev));
192
193         return 0;
194 }
195
196 static int sti_vtac_remove(struct platform_device *pdev)
197 {
198         return 0;
199 }
200
201 struct platform_driver sti_vtac_driver = {
202         .driver = {
203                 .name = "sti-vtac",
204                 .owner = THIS_MODULE,
205                 .of_match_table = vtac_of_match,
206         },
207         .probe = sti_vtac_probe,
208         .remove = sti_vtac_remove,
209 };
210
211 module_platform_driver(sti_vtac_driver);
212
213 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
214 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
215 MODULE_LICENSE("GPL");