0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/of_device.h>
0008 #include <linux/of_graph.h>
0009 #include <linux/pm_runtime.h>
0010 #include <linux/slab.h>
0011 #include <drm/drm_bridge_connector.h>
0012 #include <drm/drm_device.h>
0013 #include <drm/drm_modeset_helper.h>
0014
0015 #include "dcss-dev.h"
0016 #include "dcss-kms.h"
0017
0018 static void dcss_clocks_enable(struct dcss_dev *dcss)
0019 {
0020 clk_prepare_enable(dcss->axi_clk);
0021 clk_prepare_enable(dcss->apb_clk);
0022 clk_prepare_enable(dcss->rtrm_clk);
0023 clk_prepare_enable(dcss->dtrc_clk);
0024 clk_prepare_enable(dcss->pix_clk);
0025 }
0026
0027 static void dcss_clocks_disable(struct dcss_dev *dcss)
0028 {
0029 clk_disable_unprepare(dcss->pix_clk);
0030 clk_disable_unprepare(dcss->dtrc_clk);
0031 clk_disable_unprepare(dcss->rtrm_clk);
0032 clk_disable_unprepare(dcss->apb_clk);
0033 clk_disable_unprepare(dcss->axi_clk);
0034 }
0035
0036 static void dcss_disable_dtg_and_ss_cb(void *data)
0037 {
0038 struct dcss_dev *dcss = data;
0039
0040 dcss->disable_callback = NULL;
0041
0042 dcss_ss_shutoff(dcss->ss);
0043 dcss_dtg_shutoff(dcss->dtg);
0044
0045 complete(&dcss->disable_completion);
0046 }
0047
0048 void dcss_disable_dtg_and_ss(struct dcss_dev *dcss)
0049 {
0050 dcss->disable_callback = dcss_disable_dtg_and_ss_cb;
0051 }
0052
0053 void dcss_enable_dtg_and_ss(struct dcss_dev *dcss)
0054 {
0055 if (dcss->disable_callback)
0056 dcss->disable_callback = NULL;
0057
0058 dcss_dtg_enable(dcss->dtg);
0059 dcss_ss_enable(dcss->ss);
0060 }
0061
0062 static int dcss_submodules_init(struct dcss_dev *dcss)
0063 {
0064 int ret = 0;
0065 u32 base_addr = dcss->start_addr;
0066 const struct dcss_type_data *devtype = dcss->devtype;
0067
0068 dcss_clocks_enable(dcss);
0069
0070 ret = dcss_blkctl_init(dcss, base_addr + devtype->blkctl_ofs);
0071 if (ret)
0072 return ret;
0073
0074 ret = dcss_ctxld_init(dcss, base_addr + devtype->ctxld_ofs);
0075 if (ret)
0076 goto ctxld_err;
0077
0078 ret = dcss_dtg_init(dcss, base_addr + devtype->dtg_ofs);
0079 if (ret)
0080 goto dtg_err;
0081
0082 ret = dcss_ss_init(dcss, base_addr + devtype->ss_ofs);
0083 if (ret)
0084 goto ss_err;
0085
0086 ret = dcss_dpr_init(dcss, base_addr + devtype->dpr_ofs);
0087 if (ret)
0088 goto dpr_err;
0089
0090 ret = dcss_scaler_init(dcss, base_addr + devtype->scaler_ofs);
0091 if (ret)
0092 goto scaler_err;
0093
0094 dcss_clocks_disable(dcss);
0095
0096 return 0;
0097
0098 scaler_err:
0099 dcss_dpr_exit(dcss->dpr);
0100
0101 dpr_err:
0102 dcss_ss_exit(dcss->ss);
0103
0104 ss_err:
0105 dcss_dtg_exit(dcss->dtg);
0106
0107 dtg_err:
0108 dcss_ctxld_exit(dcss->ctxld);
0109
0110 ctxld_err:
0111 dcss_blkctl_exit(dcss->blkctl);
0112
0113 dcss_clocks_disable(dcss);
0114
0115 return ret;
0116 }
0117
0118 static void dcss_submodules_stop(struct dcss_dev *dcss)
0119 {
0120 dcss_clocks_enable(dcss);
0121 dcss_scaler_exit(dcss->scaler);
0122 dcss_dpr_exit(dcss->dpr);
0123 dcss_ss_exit(dcss->ss);
0124 dcss_dtg_exit(dcss->dtg);
0125 dcss_ctxld_exit(dcss->ctxld);
0126 dcss_blkctl_exit(dcss->blkctl);
0127 dcss_clocks_disable(dcss);
0128 }
0129
0130 static int dcss_clks_init(struct dcss_dev *dcss)
0131 {
0132 int i;
0133 struct {
0134 const char *id;
0135 struct clk **clk;
0136 } clks[] = {
0137 {"apb", &dcss->apb_clk},
0138 {"axi", &dcss->axi_clk},
0139 {"pix", &dcss->pix_clk},
0140 {"rtrm", &dcss->rtrm_clk},
0141 {"dtrc", &dcss->dtrc_clk},
0142 };
0143
0144 for (i = 0; i < ARRAY_SIZE(clks); i++) {
0145 *clks[i].clk = devm_clk_get(dcss->dev, clks[i].id);
0146 if (IS_ERR(*clks[i].clk)) {
0147 dev_err(dcss->dev, "failed to get %s clock\n",
0148 clks[i].id);
0149 return PTR_ERR(*clks[i].clk);
0150 }
0151 }
0152
0153 return 0;
0154 }
0155
0156 static void dcss_clks_release(struct dcss_dev *dcss)
0157 {
0158 devm_clk_put(dcss->dev, dcss->dtrc_clk);
0159 devm_clk_put(dcss->dev, dcss->rtrm_clk);
0160 devm_clk_put(dcss->dev, dcss->pix_clk);
0161 devm_clk_put(dcss->dev, dcss->axi_clk);
0162 devm_clk_put(dcss->dev, dcss->apb_clk);
0163 }
0164
0165 struct dcss_dev *dcss_dev_create(struct device *dev, bool hdmi_output)
0166 {
0167 struct platform_device *pdev = to_platform_device(dev);
0168 int ret;
0169 struct resource *res;
0170 struct dcss_dev *dcss;
0171 const struct dcss_type_data *devtype;
0172
0173 devtype = of_device_get_match_data(dev);
0174 if (!devtype) {
0175 dev_err(dev, "no device match found\n");
0176 return ERR_PTR(-ENODEV);
0177 }
0178
0179 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0180 if (!res) {
0181 dev_err(dev, "cannot get memory resource\n");
0182 return ERR_PTR(-EINVAL);
0183 }
0184
0185 dcss = kzalloc(sizeof(*dcss), GFP_KERNEL);
0186 if (!dcss)
0187 return ERR_PTR(-ENOMEM);
0188
0189 dcss->dev = dev;
0190 dcss->devtype = devtype;
0191 dcss->hdmi_output = hdmi_output;
0192
0193 ret = dcss_clks_init(dcss);
0194 if (ret) {
0195 dev_err(dev, "clocks initialization failed\n");
0196 goto err;
0197 }
0198
0199 dcss->of_port = of_graph_get_port_by_id(dev->of_node, 0);
0200 if (!dcss->of_port) {
0201 dev_err(dev, "no port@0 node in %s\n", dev->of_node->full_name);
0202 ret = -ENODEV;
0203 goto clks_err;
0204 }
0205
0206 dcss->start_addr = res->start;
0207
0208 ret = dcss_submodules_init(dcss);
0209 if (ret) {
0210 of_node_put(dcss->of_port);
0211 dev_err(dev, "submodules initialization failed\n");
0212 goto clks_err;
0213 }
0214
0215 init_completion(&dcss->disable_completion);
0216
0217 pm_runtime_set_autosuspend_delay(dev, 100);
0218 pm_runtime_use_autosuspend(dev);
0219 pm_runtime_set_suspended(dev);
0220 pm_runtime_allow(dev);
0221 pm_runtime_enable(dev);
0222
0223 return dcss;
0224
0225 clks_err:
0226 dcss_clks_release(dcss);
0227
0228 err:
0229 kfree(dcss);
0230
0231 return ERR_PTR(ret);
0232 }
0233
0234 void dcss_dev_destroy(struct dcss_dev *dcss)
0235 {
0236 if (!pm_runtime_suspended(dcss->dev)) {
0237 dcss_ctxld_suspend(dcss->ctxld);
0238 dcss_clocks_disable(dcss);
0239 }
0240
0241 of_node_put(dcss->of_port);
0242
0243 pm_runtime_disable(dcss->dev);
0244
0245 dcss_submodules_stop(dcss);
0246
0247 dcss_clks_release(dcss);
0248
0249 kfree(dcss);
0250 }
0251
0252 #ifdef CONFIG_PM_SLEEP
0253 int dcss_dev_suspend(struct device *dev)
0254 {
0255 struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
0256 struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
0257 struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
0258 int ret;
0259
0260 drm_bridge_connector_disable_hpd(kms->connector);
0261
0262 drm_mode_config_helper_suspend(ddev);
0263
0264 if (pm_runtime_suspended(dev))
0265 return 0;
0266
0267 ret = dcss_ctxld_suspend(dcss->ctxld);
0268 if (ret)
0269 return ret;
0270
0271 dcss_clocks_disable(dcss);
0272
0273 return 0;
0274 }
0275
0276 int dcss_dev_resume(struct device *dev)
0277 {
0278 struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
0279 struct drm_device *ddev = dcss_drv_dev_to_drm(dev);
0280 struct dcss_kms_dev *kms = container_of(ddev, struct dcss_kms_dev, base);
0281
0282 if (pm_runtime_suspended(dev)) {
0283 drm_mode_config_helper_resume(ddev);
0284 return 0;
0285 }
0286
0287 dcss_clocks_enable(dcss);
0288
0289 dcss_blkctl_cfg(dcss->blkctl);
0290
0291 dcss_ctxld_resume(dcss->ctxld);
0292
0293 drm_mode_config_helper_resume(ddev);
0294
0295 drm_bridge_connector_enable_hpd(kms->connector);
0296
0297 return 0;
0298 }
0299 #endif
0300
0301 #ifdef CONFIG_PM
0302 int dcss_dev_runtime_suspend(struct device *dev)
0303 {
0304 struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
0305 int ret;
0306
0307 ret = dcss_ctxld_suspend(dcss->ctxld);
0308 if (ret)
0309 return ret;
0310
0311 dcss_clocks_disable(dcss);
0312
0313 return 0;
0314 }
0315
0316 int dcss_dev_runtime_resume(struct device *dev)
0317 {
0318 struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dev);
0319
0320 dcss_clocks_enable(dcss);
0321
0322 dcss_blkctl_cfg(dcss->blkctl);
0323
0324 dcss_ctxld_resume(dcss->ctxld);
0325
0326 return 0;
0327 }
0328 #endif