kernel: bump 5.4 to 5.4.137
[openwrt/openwrt.git] / target / linux / layerscape / patches-5.4 / 805-display-0056-LF-794-3-gpu-cdn-imx8qm-Add-firmware-loading-support.patch
1 From 020578dd022e5d869db52e79c5aba95c1f1a84ec Mon Sep 17 00:00:00 2001
2 From: Abel Vesa <abel.vesa@nxp.com>
3 Date: Wed, 11 Dec 2019 09:21:23 +0200
4 Subject: [PATCH] LF-794-3 gpu: cdn: imx8qm: Add firmware loading support
5
6 This allows the HDP i.MX8QM driver to load the firmware on init
7 and resume. In order to have backward compatibility, if there is
8 no firmware-name property defined in the hdmi node, the driver
9 probing sequence skips the firmware loading.
10
11 Also, if u-boot has loaded already a firmware, we run with that
12 but when probing the driver, the request_firmware_nowait is used
13 to locate and keep safe the firmware for when suspend/resume happens.
14
15 This leads to 4 possible scenarios:
16
17 1. u-boot loads the firmware, the kernel driver finds the firmware
18 when rootfs is mounted. This is the most desirable scenario. Also
19 this is the only scenario that allows the hdmi to work after resume.
20
21 2. u-boot loads the firmware, the kernel driver _doesn't_ find
22 the firmware in rootfs. If there is no suspend ever happening,
23 the kernel driver will keep using the firmware that was loaded by
24 u-boot. On the first suspend/resume, the firmware is lost
25 because the HDMI IP gets powered down.
26
27 3. u-boot doesn't load the firmare, the kernel driver probing
28 tries to load the firmware, assuming this is available
29 (see CONFIG_EXTRA_FIRMWARE).
30
31 4. u-boot doesn't load the firmware and the kernel driver is not
32 able to find it either. The probing fails and there is no HDMI
33 available in linux.
34
35 Signed-off-by: Abel Vesa <abel.vesa@nxp.com>
36 Reviewed-by: Sandor Yu <sandor.yu@nxp.com>
37 Acked-by: Wen He <wen.he_1@nxp.com>
38 Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
39 ---
40 drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c | 78 +++++++++++++++++++++++++++++++++--
41 drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c | 30 ++++++++++++++
42 drivers/gpu/drm/imx/cdns-mhdp-imx.h | 4 ++
43 include/drm/bridge/cdns-mhdp-common.h | 3 ++
44 4 files changed, 111 insertions(+), 4 deletions(-)
45
46 --- a/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
47 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
48 @@ -7,12 +7,17 @@
49 */
50 #include <dt-bindings/firmware/imx/rsrc.h>
51 #include <linux/firmware/imx/sci.h>
52 +#include <linux/firmware.h>
53 #include <linux/pm_domain.h>
54 #include <linux/clk.h>
55 #include <drm/drmP.h>
56
57 #include "cdns-mhdp-imx.h"
58
59 +#define FW_IRAM_OFFSET 0x2000
60 +#define FW_IRAM_SIZE 0x10000
61 +#define FW_DRAM_SIZE 0x8000
62 +
63 #define PLL_800MHZ (800000000)
64
65 #define HDP_DUAL_MODE_MIN_PCLK_RATE 300000 /* KHz */
66 @@ -517,24 +522,69 @@ void cdns_mhdp_pclk_rate_imx8qm(struct c
67 imx8qm_pixel_link_mux(imx_mhdp);
68 }
69
70 -int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
71 +static void cdns_mhdp_firmware_load_cont(const struct firmware *fw, void *context)
72 {
73 - struct imx_mhdp_device *imx_mhdp =
74 - container_of(mhdp, struct imx_mhdp_device, mhdp);
75 + struct imx_mhdp_device *imx_mhdp = context;
76 +
77 + imx_mhdp->fw = fw;
78 +}
79 +
80 +static int cdns_mhdp_load_firmware_imx8qm(struct imx_mhdp_device *imx_mhdp)
81 +{
82 + const u8 *iram;
83 + const u8 *dram;
84 u32 rate;
85 int ret;
86
87 /* configure HDMI/DP core clock */
88 rate = clk_get_rate(imx_mhdp->clks.clk_core);
89 - if (mhdp->is_ls1028a)
90 + if (imx_mhdp->mhdp.is_ls1028a)
91 rate = rate / 4;
92
93 cdns_mhdp_set_fw_clk(&imx_mhdp->mhdp, rate);
94
95 + /* skip fw loading if none is specified */
96 + if (!imx_mhdp->firmware_name)
97 + goto out;
98 +
99 + if (!imx_mhdp->fw) {
100 + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG,
101 + imx_mhdp->firmware_name,
102 + imx_mhdp->mhdp.dev, GFP_KERNEL,
103 + imx_mhdp,
104 + cdns_mhdp_firmware_load_cont);
105 + if (ret < 0) {
106 + DRM_ERROR("failed to load firmware\n");
107 + return -ENOENT;
108 + }
109 + } else {
110 + iram = imx_mhdp->fw->data + FW_IRAM_OFFSET;
111 + dram = iram + FW_IRAM_SIZE;
112 +
113 + cdns_mhdp_load_firmware(&imx_mhdp->mhdp,
114 + (const u32 *) iram, FW_IRAM_SIZE,
115 + (const u32 *) dram, FW_DRAM_SIZE);
116 + }
117 +
118 +out:
119 /* un-reset ucpu */
120 cdns_mhdp_bus_write(0, &imx_mhdp->mhdp, APB_CTRL);
121 DRM_INFO("Started firmware!\n");
122
123 + return 0;
124 +}
125 +
126 +int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp)
127 +{
128 + struct imx_mhdp_device *imx_mhdp =
129 + container_of(mhdp, struct imx_mhdp_device, mhdp);
130 + int ret;
131 +
132 + /* load firmware */
133 + ret = cdns_mhdp_load_firmware_imx8qm(imx_mhdp);
134 + if (ret)
135 + return ret;
136 +
137 ret = cdns_mhdp_check_alive(&imx_mhdp->mhdp);
138 if (ret == false) {
139 DRM_ERROR("NO HDMI FW running\n");
140 @@ -550,3 +600,23 @@ int cdns_mhdp_firmware_init_imx8qm(struc
141
142 return 0;
143 }
144 +
145 +int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp)
146 +{
147 + struct imx_mhdp_device *imx_mhdp =
148 + container_of(mhdp, struct imx_mhdp_device, mhdp);
149 +
150 + imx8qm_pixel_clk_disable(imx_mhdp);
151 +
152 + return 0;
153 +}
154 +
155 +int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp)
156 +{
157 + struct imx_mhdp_device *imx_mhdp =
158 + container_of(mhdp, struct imx_mhdp_device, mhdp);
159 +
160 + imx8qm_pixel_clk_enable(imx_mhdp);
161 +
162 + return cdns_mhdp_firmware_init_imx8qm(mhdp);
163 +}
164 --- a/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
165 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imxdrv.c
166 @@ -82,6 +82,8 @@ static struct cdns_plat_data imx8qm_hdmi
167 .phy_video_valid = cdns_hdmi_phy_video_valid_imx8qm,
168 .power_on = cdns_mhdp_power_on_imx8qm,
169 .firmware_init = cdns_mhdp_firmware_init_imx8qm,
170 + .resume = cdns_mhdp_resume_imx8qm,
171 + .suspend = cdns_mhdp_suspend_imx8qm,
172 .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
173 .plat_init = cdns_mhdp_plat_init_imx8qm,
174 .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
175 @@ -96,6 +98,8 @@ static struct cdns_plat_data imx8qm_dp_d
176 .phy_set = cdns_dp_phy_set_imx8qm,
177 .power_on = cdns_mhdp_power_on_imx8qm,
178 .firmware_init = cdns_mhdp_firmware_init_imx8qm,
179 + .resume = cdns_mhdp_resume_imx8qm,
180 + .suspend = cdns_mhdp_suspend_imx8qm,
181 .pclk_rate = cdns_mhdp_pclk_rate_imx8qm,
182 .plat_init = cdns_mhdp_plat_init_imx8qm,
183 .plat_deinit = cdns_mhdp_plat_deinit_imx8qm,
184 @@ -157,6 +161,9 @@ static int cdns_mhdp_imx_bind(struct dev
185 encoder = &imx_mhdp->encoder;
186
187 encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
188 +
189 + ret = of_property_read_string(pdev->dev.of_node, "firmware-name",
190 + &imx_mhdp->firmware_name);
191 /*
192 * If we failed to find the CRTC(s) which this encoder is
193 * supposed to be connected to, it's because the CRTC has
194 @@ -198,6 +205,24 @@ static const struct component_ops cdns_m
195 .unbind = cdns_mhdp_imx_unbind,
196 };
197
198 +static int cdns_mhdp_imx_suspend(struct device *dev)
199 +{
200 + struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
201 +
202 + cdns_mhdp_plat_call(&imx_mhdp->mhdp, suspend);
203 +
204 + return 0;
205 +}
206 +
207 +static int cdns_mhdp_imx_resume(struct device *dev)
208 +{
209 + struct imx_mhdp_device *imx_mhdp = dev_get_drvdata(dev);
210 +
211 + cdns_mhdp_plat_call(&imx_mhdp->mhdp, resume);
212 +
213 + return 0;
214 +}
215 +
216 static int cdns_mhdp_imx_probe(struct platform_device *pdev)
217 {
218 return component_add(&pdev->dev, &cdns_mhdp_imx_ops);
219 @@ -210,12 +235,17 @@ static int cdns_mhdp_imx_remove(struct p
220 return 0;
221 }
222
223 +static const struct dev_pm_ops cdns_mhdp_imx_pm_ops = {
224 + SET_LATE_SYSTEM_SLEEP_PM_OPS(cdns_mhdp_imx_suspend, cdns_mhdp_imx_resume)
225 +};
226 +
227 static struct platform_driver cdns_mhdp_imx_platform_driver = {
228 .probe = cdns_mhdp_imx_probe,
229 .remove = cdns_mhdp_imx_remove,
230 .driver = {
231 .name = "cdns-mhdp-imx",
232 .of_match_table = cdns_mhdp_imx_dt_ids,
233 + .pm = &cdns_mhdp_imx_pm_ops,
234 },
235 };
236
237 --- a/drivers/gpu/drm/imx/cdns-mhdp-imx.h
238 +++ b/drivers/gpu/drm/imx/cdns-mhdp-imx.h
239 @@ -50,6 +50,8 @@ struct imx_mhdp_device {
240 bool active;
241 bool suspended;
242 struct imx_hdp_clks clks;
243 + const struct firmware *fw;
244 + const char *firmware_name;
245
246 int bus_type;
247
248 @@ -65,6 +67,8 @@ void cdns_mhdp_plat_init_imx8qm(struct c
249 void cdns_mhdp_plat_deinit_imx8qm(struct cdns_mhdp_device *mhdp);
250 void cdns_mhdp_pclk_rate_imx8qm(struct cdns_mhdp_device *mhdp);
251 int cdns_mhdp_firmware_init_imx8qm(struct cdns_mhdp_device *mhdp);
252 +int cdns_mhdp_resume_imx8qm(struct cdns_mhdp_device *mhdp);
253 +int cdns_mhdp_suspend_imx8qm(struct cdns_mhdp_device *mhdp);
254 int cdns_mhdp_power_on_imx8qm(struct cdns_mhdp_device *mhdp);
255 int cdns_mhdp_power_on_ls1028a(struct cdns_mhdp_device *mhdp);
256 void cdns_mhdp_pclk_rate_ls1028a(struct cdns_mhdp_device *mhdp);
257 --- a/include/drm/bridge/cdns-mhdp-common.h
258 +++ b/include/drm/bridge/cdns-mhdp-common.h
259 @@ -645,6 +645,9 @@ struct cdns_plat_data {
260 int (*firmware_init)(struct cdns_mhdp_device *mhdp);
261 void (*pclk_rate)(struct cdns_mhdp_device *mhdp);
262
263 + int (*suspend)(struct cdns_mhdp_device *mhdp);
264 + int (*resume)(struct cdns_mhdp_device *mhdp);
265 +
266 int (*power_on)(struct cdns_mhdp_device *mhdp);
267 int (*power_off)(struct cdns_mhdp_device *mhdp);
268