ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 805-display-0008-drm-bridge-cadence-Add-CEC-driver-for-cdns-mhdp-hdmi.patch
1 From ed9e7a6b3346b186a7bd22d9b62072e55ff7b9c5 Mon Sep 17 00:00:00 2001
2 From: Sandor Yu <Sandor.yu@nxp.com>
3 Date: Mon, 2 Sep 2019 14:57:05 +0800
4 Subject: [PATCH] drm: bridge: cadence: Add CEC driver for cdns mhdp hdmi
5
6 Add cec driver for cdns mhdp hdmi.
7
8 Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
9 ---
10  drivers/gpu/drm/bridge/cadence/Kconfig            |   3 +
11  drivers/gpu/drm/bridge/cadence/Makefile           |   1 +
12  drivers/gpu/drm/bridge/cadence/cdns-dp-core.c     |   0
13  drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c   |   9 +
14  drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c    | 347 ++++++++++++++++++++++
15  drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c |   0
16  drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c   |   0
17  include/drm/bridge/cdns-mhdp-common.h             |  24 +-
18  8 files changed, 382 insertions(+), 2 deletions(-)
19  mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-dp-core.c
20  mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
21  create mode 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
22  mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-common.c
23  mode change 100755 => 100644 drivers/gpu/drm/bridge/cadence/cdns-mhdp-hdmi.c
24
25 --- a/drivers/gpu/drm/bridge/cadence/Kconfig
26 +++ b/drivers/gpu/drm/bridge/cadence/Kconfig
27 @@ -14,3 +14,6 @@ config DRM_CDNS_DP
28  
29  config DRM_CDNS_AUDIO
30         tristate "Cadence MHDP Audio driver"
31 +
32 +config DRM_CDNS_HDMI_CEC
33 +       tristate "Cadence MHDP HDMI CEC driver"
34 --- a/drivers/gpu/drm/bridge/cadence/Makefile
35 +++ b/drivers/gpu/drm/bridge/cadence/Makefile
36 @@ -2,3 +2,4 @@ obj-$(CONFIG_DRM_CDNS_MHDP) += cdns-mhdp
37  obj-$(CONFIG_DRM_CDNS_HDMI) += cdns-hdmi-core.o
38  obj-$(CONFIG_DRM_CDNS_DP) += cdns-dp-core.o
39  obj-$(CONFIG_DRM_CDNS_AUDIO) += cdns-mhdp-audio.o
40 +obj-$(CONFIG_DRM_CDNS_HDMI_CEC) += cdns-mhdp-cec.o
41 --- a/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
42 +++ b/drivers/gpu/drm/bridge/cadence/cdns-hdmi-core.c
43 @@ -515,6 +515,11 @@ __cdns_hdmi_probe(struct platform_device
44         /* register audio driver */
45         cdns_mhdp_register_audio_driver(dev);
46  
47 +       /* register cec driver */
48 +#ifdef CONFIG_DRM_CDNS_HDMI_CEC
49 +       cdns_mhdp_register_cec_driver(dev);
50 +#endif
51 +
52         return hdmi;
53  
54  err_out:
55 @@ -524,6 +529,10 @@ err_out:
56  
57  static void __cdns_hdmi_remove(struct cdns_mhdp_device *mhdp)
58  {
59 +       /* unregister cec driver */
60 +#ifdef CONFIG_DRM_CDNS_HDMI_CEC
61 +       cdns_mhdp_unregister_cec_driver(mhdp->dev);
62 +#endif
63         cdns_mhdp_unregister_audio_driver(mhdp->dev);
64  }
65  
66 --- /dev/null
67 +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp-cec.c
68 @@ -0,0 +1,347 @@
69 +/*
70 + * Copyright 2019 NXP
71 + *
72 + * This program is free software; you can redistribute it and/or
73 + * modify it under the terms of the GNU General Public License
74 + * as published by the Free Software Foundation; either version 2
75 + * of the License, or (at your option) any later version.
76 + *
77 + * This program is distributed in the hope that it will be useful,
78 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
79 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
80 + * GNU General Public License for more details.
81 + */
82 +#include <linux/module.h>
83 +#include <linux/workqueue.h>
84 +#include <linux/kthread.h>
85 +#include <linux/freezer.h>
86 +#include <drm/bridge/cdns-mhdp-common.h>
87 +
88 +#define CEC_NAME       "cdns-mhdp-cec"
89 +
90 +#define REG_ADDR_OFF 4
91 +#define MAX_LA_IDX 4
92 +#define MAX_LA_VAL 15
93 +
94 +/* regsiter define */
95 +#define TX_MSG_HEADER 0x33800
96 +#define TX_MSG_LENGTH 0x33840
97 +#define TX_MSG_CMD 0x33844
98 +#define RX_MSG_CMD 0x33850
99 +#define RX_CLEAR_BUF 0x33854
100 +#define LOGICAL_ADDRESS_LA0 0x33858
101 +
102 +#define CLK_DIV_MSB 0x3386c
103 +#define CLK_DIV_LSB 0x33870
104 +#define RX_MSG_DATA1 0x33900
105 +#define RX_MSG_LENGTH 0x33940
106 +#define RX_MSG_STATUS 0x33944
107 +#define NUM_OF_MSG_RX_BUF 0x33948
108 +#define TX_MSG_STATUS 0x3394c
109 +#define DB_L_TIMER 0x33980
110 +
111 +/**
112 + * CEC Transceiver operation.
113 + */
114 +enum {
115 +       CEC_TX_STOP,
116 +       CEC_TX_TRANSMIT,
117 +       CEC_TX_ABORT,
118 +       CEC_TX_ABORT_AND_TRANSMIT
119 +};
120 +
121 +/**
122 + * CEC Transceiver status.
123 + */
124 +enum {
125 +       CEC_STS_IDLE,
126 +       CEC_STS_BUSY,
127 +       CEC_STS_SUCCESS,
128 +       CEC_STS_ERROR
129 +};
130 +
131 +/**
132 + * CEC Receiver operation.
133 + */
134 +enum {
135 +       CEC_RX_STOP,
136 +       CEC_RX_READ,
137 +       CEC_RX_DISABLE,
138 +       CEC_RX_ABORT_AND_CLR_FIFO
139 +};
140 +/**
141 + * Maximum number of Messages in the RX Buffers.
142 + */
143 +#define CEC_MAX_RX_MSGS 2
144 +
145 +static u32 mhdp_cec_read(struct cdns_mhdp_cec *cec, u32 offset)
146 +{
147 +       struct cdns_mhdp_device *mhdp =
148 +                       container_of(cec, struct cdns_mhdp_device, hdmi.cec);
149 +       return cdns_mhdp_bus_read(mhdp, offset);
150 +}
151 +
152 +static void mhdp_cec_write(struct cdns_mhdp_cec *cec, u32 offset, u32 val)
153 +{
154 +       struct cdns_mhdp_device *mhdp =
155 +                       container_of(cec, struct cdns_mhdp_device, hdmi.cec);
156 +       cdns_mhdp_bus_write(val, mhdp, offset);
157 +}
158 +
159 +static void mhdp_cec_clear_rx_buffer(struct cdns_mhdp_cec *cec)
160 +{
161 +       mhdp_cec_write(cec, RX_CLEAR_BUF, 1);
162 +       mhdp_cec_write(cec, RX_CLEAR_BUF, 0);
163 +}
164 +
165 +static void mhdp_cec_set_divider(struct cdns_mhdp_cec *cec)
166 +{
167 +       struct cdns_mhdp_device *mhdp =
168 +                       container_of(cec, struct cdns_mhdp_device, hdmi.cec);
169 +       u32 clk_div;
170 +
171 +       /* Set clock divider */
172 +       clk_div = cdns_mhdp_get_fw_clk(mhdp) * 10;
173 +
174 +       mhdp_cec_write(cec, CLK_DIV_MSB,
175 +                         (clk_div >> 8) & 0xFF);
176 +       mhdp_cec_write(cec, CLK_DIV_LSB, clk_div & 0xFF);
177 +}
178 +
179 +static u32 mhdp_cec_read_message(struct cdns_mhdp_cec *cec)
180 +{
181 +       struct cec_msg *msg = &cec->msg;
182 +       int len;
183 +       int i;
184 +
185 +       mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_READ);
186 +
187 +       len = mhdp_cec_read(cec, RX_MSG_LENGTH);
188 +       msg->len = len + 1;
189 +       dev_dbg(cec->dev, "RX MSG len =%d\n", len);
190 +
191 +       /* Read RX MSG bytes */
192 +       for (i = 0; i < msg->len; ++i) {
193 +               msg->msg[i] = (u8) mhdp_cec_read(cec, RX_MSG_DATA1 + (i * REG_ADDR_OFF));
194 +               dev_dbg(cec->dev, "RX MSG[%d]=0x%x\n", i, msg->msg[i]);
195 +       }
196 +
197 +       mhdp_cec_write(cec, RX_MSG_CMD, CEC_RX_STOP);
198 +
199 +       return true;
200 +}
201 +
202 +static u32 mhdp_cec_write_message(struct cdns_mhdp_cec *cec, struct cec_msg *msg)
203 +{
204 +       u8 i;
205 +
206 +       mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
207 +
208 +       if (msg->len > CEC_MAX_MSG_SIZE) {
209 +               dev_err(cec->dev, "Invalid MSG size!\n");
210 +               return -EINVAL;
211 +       }
212 +
213 +       for (i = 0; i < msg->len; ++i)
214 +               printk("msg[%d]=0x%x\n",i, msg->msg[i]);
215 +
216 +       /* Write Message to register */
217 +       for (i = 0; i < msg->len; ++i) {
218 +               mhdp_cec_write(cec, TX_MSG_HEADER + (i * REG_ADDR_OFF),
219 +                         msg->msg[i]);
220 +       }
221 +       /* Write Message Length (payload + opcode) */
222 +       mhdp_cec_write(cec, TX_MSG_LENGTH, msg->len - 1);
223 +
224 +       mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_TRANSMIT);
225 +
226 +       return true;
227 +}
228 +
229 +//static void cec_abort_tx_transfer(struct cdns_mhdp_cec *cec)
230 +//{
231 +//     cec_write(cec, TX_MSG_CMD, CEC_TX_ABORT);
232 +//     cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
233 +//}
234 +
235 +static int mhdp_cec_set_logical_addr(struct cdns_mhdp_cec *cec, u32 la)
236 +{
237 +       u8 i;
238 +       u8 la_reg;
239 +
240 +       if (la >= MAX_LA_VAL) {
241 +               dev_err(cec->dev, "Error logical Addr\n");
242 +               return -EINVAL;
243 +       }
244 +
245 +       for (i = 0; i < MAX_LA_IDX; ++i) {
246 +               la_reg =
247 +                   mhdp_cec_read(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF));
248 +
249 +               if (la_reg & 0x10)
250 +                       continue;
251 +
252 +               if ((la_reg & 0xF) == la) {
253 +                       dev_warn(cec->dev, "Warning. LA already in use.\n");
254 +                       return true;
255 +               }
256 +
257 +               la = (la & 0xF) | (1 << 4);
258 +
259 +               mhdp_cec_write(cec, LOGICAL_ADDRESS_LA0 + (i * REG_ADDR_OFF), la);
260 +               return true;
261 +       }
262 +
263 +       dev_warn(cec->dev, "All LA in use\n");
264 +
265 +       return false;
266 +}
267 +
268 +static int mhdp_cec_poll_worker(void *_cec)
269 +{
270 +       struct cdns_mhdp_cec *cec = (struct cdns_mhdp_cec *)_cec;
271 +       int num_rx_msgs, i;
272 +       int sts;
273 +
274 +       set_freezable();
275 +
276 +       for (;;) {
277 +               if (kthread_freezable_should_stop(NULL))
278 +                       break;
279 +
280 +               /* Check TX State */
281 +               sts = mhdp_cec_read(cec, TX_MSG_STATUS);
282 +               switch (sts) {
283 +               case CEC_STS_SUCCESS:
284 +                       cec_transmit_done(cec->adap, CEC_TX_STATUS_OK, 0, 0, 0,
285 +                                         0);
286 +                       mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
287 +                       break;
288 +               case CEC_STS_ERROR:
289 +                       mhdp_cec_write(cec, TX_MSG_CMD, CEC_TX_STOP);
290 +                       cec_transmit_done(cec->adap,
291 +                                         CEC_TX_STATUS_MAX_RETRIES |
292 +                                         CEC_TX_STATUS_NACK, 0, 1, 0, 0);
293 +                       break;
294 +               case CEC_STS_BUSY:
295 +               default:
296 +                       break;
297 +               }
298 +
299 +               /* Check RX State */
300 +               sts = mhdp_cec_read(cec, RX_MSG_STATUS);
301 +               num_rx_msgs = mhdp_cec_read(cec, NUM_OF_MSG_RX_BUF);
302 +               switch (sts) {
303 +               case CEC_STS_SUCCESS:
304 +                       if (num_rx_msgs == 0xf)
305 +                               num_rx_msgs = CEC_MAX_RX_MSGS;
306 +
307 +                       if (num_rx_msgs > CEC_MAX_RX_MSGS) {
308 +                               dev_err(cec->dev, "Error rx msg num %d\n",
309 +                                       num_rx_msgs);
310 +                               mhdp_cec_clear_rx_buffer(cec);
311 +                               break;
312 +                       }
313 +
314 +                       /* Rx FIFO Depth 2 RX MSG */
315 +                       for (i = 0; i < num_rx_msgs; i++) {
316 +                               mhdp_cec_read_message(cec);
317 +                               cec->msg.rx_status = CEC_RX_STATUS_OK;
318 +                               cec_received_msg(cec->adap, &cec->msg);
319 +                       }
320 +                       break;
321 +               default:
322 +                       break;
323 +               }
324 +
325 +               if (!kthread_should_stop())
326 +                       schedule_timeout_idle(20);
327 +       }
328 +
329 +       return 0;
330 +}
331 +
332 +static int mhdp_cec_adap_enable(struct cec_adapter *adap, bool enable)
333 +{
334 +       struct cdns_mhdp_cec *cec = adap->priv;
335 +
336 +       if (enable) {
337 +               mhdp_cec_write(cec, DB_L_TIMER, 0x10);
338 +               mhdp_cec_set_divider(cec);
339 +       } else
340 +               mhdp_cec_set_divider(cec);
341 +
342 +       return 0;
343 +}
344 +
345 +static int mhdp_cec_adap_log_addr(struct cec_adapter *adap, u8 addr)
346 +{
347 +       struct cdns_mhdp_cec *cec = adap->priv;
348 +
349 +       return mhdp_cec_set_logical_addr(cec, addr);
350 +}
351 +
352 +static int mhdp_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
353 +                                u32 signal_free_time, struct cec_msg *msg)
354 +{
355 +       struct cdns_mhdp_cec *cec = adap->priv;
356 +
357 +       mhdp_cec_write_message(cec, msg);
358 +
359 +       return 0;
360 +}
361 +
362 +static const struct cec_adap_ops cdns_mhdp_cec_adap_ops = {
363 +       .adap_enable = mhdp_cec_adap_enable,
364 +       .adap_log_addr = mhdp_cec_adap_log_addr,
365 +       .adap_transmit = mhdp_cec_adap_transmit,
366 +};
367 +
368 +int cdns_mhdp_register_cec_driver(struct device *dev)
369 +{
370 +       struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
371 +       struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
372 +       int ret;
373 +
374 +       cec->adap = cec_allocate_adapter(&cdns_mhdp_cec_adap_ops, cec,
375 +                                        CEC_NAME,
376 +                                        CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS |
377 +                                        CEC_CAP_TRANSMIT | CEC_CAP_PASSTHROUGH
378 +                                        | CEC_CAP_RC, 1);
379 +       ret = PTR_ERR_OR_ZERO(cec->adap);
380 +       if (ret)
381 +               return ret;
382 +       ret = cec_register_adapter(cec->adap, dev);
383 +       if (ret) {
384 +               cec_delete_adapter(cec->adap);
385 +               return ret;
386 +       }
387 +
388 +       cec->dev = dev;
389 +
390 +       cec->cec_worker = kthread_create(mhdp_cec_poll_worker, cec, "cdns-mhdp-cec");
391 +       if (IS_ERR(cec->cec_worker))
392 +               dev_err(cec->dev, "failed  create hdp cec thread\n");
393 +
394 +       wake_up_process(cec->cec_worker);
395 +
396 +       dev_dbg(dev, "CEC successfuly probed\n");
397 +       return 0;
398 +}
399 +
400 +int cdns_mhdp_unregister_cec_driver(struct device *dev)
401 +{
402 +       struct cdns_mhdp_device *mhdp = dev_get_drvdata(dev);
403 +       struct cdns_mhdp_cec *cec = &mhdp->hdmi.cec;
404 +
405 +       if (cec->cec_worker) {
406 +               kthread_stop(cec->cec_worker);
407 +               cec->cec_worker = NULL;
408 +       }
409 +       cec_unregister_adapter(cec->adap);
410 +       return 0;
411 +}
412 +
413 +MODULE_AUTHOR("Sandor.Yu@NXP.com");
414 +MODULE_LICENSE("GPL");
415 +MODULE_DESCRIPTION("NXP CDNS MHDP CEC driver");
416 --- a/include/drm/bridge/cdns-mhdp-common.h
417 +++ b/include/drm/bridge/cdns-mhdp-common.h
418 @@ -21,7 +21,7 @@
419  #include <drm/drm_connector.h>
420  #include <drm/drm_dp_helper.h>
421  #include <drm/drm_dp_mst_helper.h>
422 -
423 +#include <media/cec.h>
424  #include <linux/bitops.h>
425  
426  #define ADDR_IMEM              0x10000
427 @@ -605,6 +605,17 @@ struct cdns_mhdp_connector {
428         struct cdns_mhdp_bridge *bridge;
429  };
430  
431 +#ifdef CONFIG_DRM_CDNS_HDMI_CEC
432 +struct cdns_mhdp_cec {
433 +       struct cec_adapter *adap;
434 +       struct device *dev;
435 +       struct mutex lock;
436 +
437 +       struct cec_msg msg;
438 +       struct task_struct *cec_worker;
439 +};
440 +#endif
441 +
442  struct cdns_mhdp_device {
443         void __iomem            *regs;
444  
445 @@ -633,7 +644,7 @@ struct cdns_mhdp_device {
446         bool plugged;
447  
448         union {
449 -               struct cdn_dp_data {
450 +               struct _dp_data {
451                         struct drm_dp_link      link;
452                         struct drm_dp_aux       aux;
453                         struct cdns_mhdp_host   host;
454 @@ -645,6 +656,9 @@ struct cdns_mhdp_device {
455                         u32 num_lanes;
456                 } dp;
457                 struct _hdmi_data {
458 +#ifdef CONFIG_DRM_CDNS_HDMI_CEC
459 +                       struct cdns_mhdp_cec cec;
460 +#endif
461                         u32 char_rate;
462                         u32 hdmi_type;
463                 } hdmi;
464 @@ -713,4 +727,10 @@ int cdns_hdmi_disable_gcp(struct cdns_mh
465  int cdns_hdmi_enable_gcp(struct cdns_mhdp_device *mhdp);
466  
467  bool cdns_mhdp_check_alive(struct cdns_mhdp_device *mhdp);
468 +/* CEC */
469 +#ifdef CONFIG_DRM_CDNS_HDMI_CEC
470 +int cdns_mhdp_register_cec_driver(struct device *dev);
471 +int cdns_mhdp_unregister_cec_driver(struct device *dev);
472 +#endif
473 +
474  #endif /* CDNS_MHDP_COMMON_H_ */