Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2012-2013, NVIDIA Corporation.
0004  */
0005 
0006 #include <linux/clk.h>
0007 #include <linux/delay.h>
0008 #include <linux/iommu.h>
0009 #include <linux/module.h>
0010 #include <linux/of_device.h>
0011 #include <linux/pm_runtime.h>
0012 #include <linux/reset.h>
0013 
0014 #include <soc/tegra/common.h>
0015 
0016 #include "drm.h"
0017 #include "gem.h"
0018 #include "gr2d.h"
0019 
0020 enum {
0021     RST_MC,
0022     RST_GR2D,
0023     RST_GR2D_MAX,
0024 };
0025 
0026 struct gr2d_soc {
0027     unsigned int version;
0028 };
0029 
0030 struct gr2d {
0031     struct tegra_drm_client client;
0032     struct host1x_channel *channel;
0033     struct clk *clk;
0034 
0035     struct reset_control_bulk_data resets[RST_GR2D_MAX];
0036     unsigned int nresets;
0037 
0038     const struct gr2d_soc *soc;
0039 
0040     DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS);
0041 };
0042 
0043 static inline struct gr2d *to_gr2d(struct tegra_drm_client *client)
0044 {
0045     return container_of(client, struct gr2d, client);
0046 }
0047 
0048 static int gr2d_init(struct host1x_client *client)
0049 {
0050     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0051     struct drm_device *dev = dev_get_drvdata(client->host);
0052     unsigned long flags = HOST1X_SYNCPT_HAS_BASE;
0053     struct gr2d *gr2d = to_gr2d(drm);
0054     int err;
0055 
0056     gr2d->channel = host1x_channel_request(client);
0057     if (!gr2d->channel)
0058         return -ENOMEM;
0059 
0060     client->syncpts[0] = host1x_syncpt_request(client, flags);
0061     if (!client->syncpts[0]) {
0062         err = -ENOMEM;
0063         dev_err(client->dev, "failed to request syncpoint: %d\n", err);
0064         goto put;
0065     }
0066 
0067     err = host1x_client_iommu_attach(client);
0068     if (err < 0) {
0069         dev_err(client->dev, "failed to attach to domain: %d\n", err);
0070         goto free;
0071     }
0072 
0073     pm_runtime_enable(client->dev);
0074     pm_runtime_use_autosuspend(client->dev);
0075     pm_runtime_set_autosuspend_delay(client->dev, 200);
0076 
0077     err = tegra_drm_register_client(dev->dev_private, drm);
0078     if (err < 0) {
0079         dev_err(client->dev, "failed to register client: %d\n", err);
0080         goto disable_rpm;
0081     }
0082 
0083     return 0;
0084 
0085 disable_rpm:
0086     pm_runtime_dont_use_autosuspend(client->dev);
0087     pm_runtime_force_suspend(client->dev);
0088 
0089     host1x_client_iommu_detach(client);
0090 free:
0091     host1x_syncpt_put(client->syncpts[0]);
0092 put:
0093     host1x_channel_put(gr2d->channel);
0094     return err;
0095 }
0096 
0097 static int gr2d_exit(struct host1x_client *client)
0098 {
0099     struct tegra_drm_client *drm = host1x_to_drm_client(client);
0100     struct drm_device *dev = dev_get_drvdata(client->host);
0101     struct tegra_drm *tegra = dev->dev_private;
0102     struct gr2d *gr2d = to_gr2d(drm);
0103     int err;
0104 
0105     err = tegra_drm_unregister_client(tegra, drm);
0106     if (err < 0)
0107         return err;
0108 
0109     pm_runtime_dont_use_autosuspend(client->dev);
0110     pm_runtime_force_suspend(client->dev);
0111 
0112     host1x_client_iommu_detach(client);
0113     host1x_syncpt_put(client->syncpts[0]);
0114     host1x_channel_put(gr2d->channel);
0115 
0116     gr2d->channel = NULL;
0117 
0118     return 0;
0119 }
0120 
0121 static const struct host1x_client_ops gr2d_client_ops = {
0122     .init = gr2d_init,
0123     .exit = gr2d_exit,
0124 };
0125 
0126 static int gr2d_open_channel(struct tegra_drm_client *client,
0127                  struct tegra_drm_context *context)
0128 {
0129     struct gr2d *gr2d = to_gr2d(client);
0130 
0131     context->channel = host1x_channel_get(gr2d->channel);
0132     if (!context->channel)
0133         return -ENOMEM;
0134 
0135     return 0;
0136 }
0137 
0138 static void gr2d_close_channel(struct tegra_drm_context *context)
0139 {
0140     host1x_channel_put(context->channel);
0141 }
0142 
0143 static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset)
0144 {
0145     struct gr2d *gr2d = dev_get_drvdata(dev);
0146 
0147     switch (class) {
0148     case HOST1X_CLASS_HOST1X:
0149         if (offset == 0x2b)
0150             return 1;
0151 
0152         break;
0153 
0154     case HOST1X_CLASS_GR2D:
0155     case HOST1X_CLASS_GR2D_SB:
0156         if (offset >= GR2D_NUM_REGS)
0157             break;
0158 
0159         if (test_bit(offset, gr2d->addr_regs))
0160             return 1;
0161 
0162         break;
0163     }
0164 
0165     return 0;
0166 }
0167 
0168 static int gr2d_is_valid_class(u32 class)
0169 {
0170     return (class == HOST1X_CLASS_GR2D ||
0171         class == HOST1X_CLASS_GR2D_SB);
0172 }
0173 
0174 static const struct tegra_drm_client_ops gr2d_ops = {
0175     .open_channel = gr2d_open_channel,
0176     .close_channel = gr2d_close_channel,
0177     .is_addr_reg = gr2d_is_addr_reg,
0178     .is_valid_class = gr2d_is_valid_class,
0179     .submit = tegra_drm_submit,
0180 };
0181 
0182 static const struct gr2d_soc tegra20_gr2d_soc = {
0183     .version = 0x20,
0184 };
0185 
0186 static const struct gr2d_soc tegra30_gr2d_soc = {
0187     .version = 0x30,
0188 };
0189 
0190 static const struct gr2d_soc tegra114_gr2d_soc = {
0191     .version = 0x35,
0192 };
0193 
0194 static const struct of_device_id gr2d_match[] = {
0195     { .compatible = "nvidia,tegra114-gr2d", .data = &tegra114_gr2d_soc },
0196     { .compatible = "nvidia,tegra30-gr2d", .data = &tegra30_gr2d_soc },
0197     { .compatible = "nvidia,tegra20-gr2d", .data = &tegra20_gr2d_soc },
0198     { },
0199 };
0200 MODULE_DEVICE_TABLE(of, gr2d_match);
0201 
0202 static const u32 gr2d_addr_regs[] = {
0203     GR2D_UA_BASE_ADDR,
0204     GR2D_VA_BASE_ADDR,
0205     GR2D_PAT_BASE_ADDR,
0206     GR2D_DSTA_BASE_ADDR,
0207     GR2D_DSTB_BASE_ADDR,
0208     GR2D_DSTC_BASE_ADDR,
0209     GR2D_SRCA_BASE_ADDR,
0210     GR2D_SRCB_BASE_ADDR,
0211     GR2D_PATBASE_ADDR,
0212     GR2D_SRC_BASE_ADDR_SB,
0213     GR2D_DSTA_BASE_ADDR_SB,
0214     GR2D_DSTB_BASE_ADDR_SB,
0215     GR2D_UA_BASE_ADDR_SB,
0216     GR2D_VA_BASE_ADDR_SB,
0217 };
0218 
0219 static int gr2d_get_resets(struct device *dev, struct gr2d *gr2d)
0220 {
0221     int err;
0222 
0223     gr2d->resets[RST_MC].id = "mc";
0224     gr2d->resets[RST_GR2D].id = "2d";
0225     gr2d->nresets = RST_GR2D_MAX;
0226 
0227     err = devm_reset_control_bulk_get_optional_exclusive_released(
0228                 dev, gr2d->nresets, gr2d->resets);
0229     if (err) {
0230         dev_err(dev, "failed to get reset: %d\n", err);
0231         return err;
0232     }
0233 
0234     if (WARN_ON(!gr2d->resets[RST_GR2D].rstc))
0235         return -ENOENT;
0236 
0237     return 0;
0238 }
0239 
0240 static int gr2d_probe(struct platform_device *pdev)
0241 {
0242     struct device *dev = &pdev->dev;
0243     struct host1x_syncpt **syncpts;
0244     struct gr2d *gr2d;
0245     unsigned int i;
0246     int err;
0247 
0248     gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL);
0249     if (!gr2d)
0250         return -ENOMEM;
0251 
0252     platform_set_drvdata(pdev, gr2d);
0253 
0254     gr2d->soc = of_device_get_match_data(dev);
0255 
0256     syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
0257     if (!syncpts)
0258         return -ENOMEM;
0259 
0260     gr2d->clk = devm_clk_get(dev, NULL);
0261     if (IS_ERR(gr2d->clk)) {
0262         dev_err(dev, "cannot get clock\n");
0263         return PTR_ERR(gr2d->clk);
0264     }
0265 
0266     err = gr2d_get_resets(dev, gr2d);
0267     if (err)
0268         return err;
0269 
0270     INIT_LIST_HEAD(&gr2d->client.base.list);
0271     gr2d->client.base.ops = &gr2d_client_ops;
0272     gr2d->client.base.dev = dev;
0273     gr2d->client.base.class = HOST1X_CLASS_GR2D;
0274     gr2d->client.base.syncpts = syncpts;
0275     gr2d->client.base.num_syncpts = 1;
0276 
0277     INIT_LIST_HEAD(&gr2d->client.list);
0278     gr2d->client.version = gr2d->soc->version;
0279     gr2d->client.ops = &gr2d_ops;
0280 
0281     err = devm_tegra_core_dev_init_opp_table_common(dev);
0282     if (err)
0283         return err;
0284 
0285     err = host1x_client_register(&gr2d->client.base);
0286     if (err < 0) {
0287         dev_err(dev, "failed to register host1x client: %d\n", err);
0288         return err;
0289     }
0290 
0291     /* initialize address register map */
0292     for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++)
0293         set_bit(gr2d_addr_regs[i], gr2d->addr_regs);
0294 
0295     return 0;
0296 }
0297 
0298 static int gr2d_remove(struct platform_device *pdev)
0299 {
0300     struct gr2d *gr2d = platform_get_drvdata(pdev);
0301     int err;
0302 
0303     err = host1x_client_unregister(&gr2d->client.base);
0304     if (err < 0) {
0305         dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
0306             err);
0307         return err;
0308     }
0309 
0310     return 0;
0311 }
0312 
0313 static int __maybe_unused gr2d_runtime_suspend(struct device *dev)
0314 {
0315     struct gr2d *gr2d = dev_get_drvdata(dev);
0316     int err;
0317 
0318     host1x_channel_stop(gr2d->channel);
0319     reset_control_bulk_release(gr2d->nresets, gr2d->resets);
0320 
0321     /*
0322      * GR2D module shouldn't be reset while hardware is idling, otherwise
0323      * host1x's cmdproc will stuck on trying to access any G2 register
0324      * after reset. GR2D module could be either hot-reset or reset after
0325      * power-gating of the HEG partition. Hence we will put in reset only
0326      * the memory client part of the module, the HEG GENPD will take care
0327      * of resetting GR2D module across power-gating.
0328      *
0329      * On Tegra20 there is no HEG partition, but it's okay to have
0330      * undetermined h/w state since userspace is expected to reprogram
0331      * the state on each job submission anyways.
0332      */
0333     err = reset_control_acquire(gr2d->resets[RST_MC].rstc);
0334     if (err) {
0335         dev_err(dev, "failed to acquire MC reset: %d\n", err);
0336         goto acquire_reset;
0337     }
0338 
0339     err = reset_control_assert(gr2d->resets[RST_MC].rstc);
0340     reset_control_release(gr2d->resets[RST_MC].rstc);
0341     if (err) {
0342         dev_err(dev, "failed to assert MC reset: %d\n", err);
0343         goto acquire_reset;
0344     }
0345 
0346     clk_disable_unprepare(gr2d->clk);
0347 
0348     return 0;
0349 
0350 acquire_reset:
0351     reset_control_bulk_acquire(gr2d->nresets, gr2d->resets);
0352     reset_control_bulk_deassert(gr2d->nresets, gr2d->resets);
0353 
0354     return err;
0355 }
0356 
0357 static int __maybe_unused gr2d_runtime_resume(struct device *dev)
0358 {
0359     struct gr2d *gr2d = dev_get_drvdata(dev);
0360     int err;
0361 
0362     err = reset_control_bulk_acquire(gr2d->nresets, gr2d->resets);
0363     if (err) {
0364         dev_err(dev, "failed to acquire reset: %d\n", err);
0365         return err;
0366     }
0367 
0368     err = clk_prepare_enable(gr2d->clk);
0369     if (err) {
0370         dev_err(dev, "failed to enable clock: %d\n", err);
0371         goto release_reset;
0372     }
0373 
0374     usleep_range(2000, 4000);
0375 
0376     /* this is a reset array which deasserts both 2D MC and 2D itself */
0377     err = reset_control_bulk_deassert(gr2d->nresets, gr2d->resets);
0378     if (err) {
0379         dev_err(dev, "failed to deassert reset: %d\n", err);
0380         goto disable_clk;
0381     }
0382 
0383     return 0;
0384 
0385 disable_clk:
0386     clk_disable_unprepare(gr2d->clk);
0387 release_reset:
0388     reset_control_bulk_release(gr2d->nresets, gr2d->resets);
0389 
0390     return err;
0391 }
0392 
0393 static const struct dev_pm_ops tegra_gr2d_pm = {
0394     SET_RUNTIME_PM_OPS(gr2d_runtime_suspend, gr2d_runtime_resume, NULL)
0395     SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
0396                 pm_runtime_force_resume)
0397 };
0398 
0399 struct platform_driver tegra_gr2d_driver = {
0400     .driver = {
0401         .name = "tegra-gr2d",
0402         .of_match_table = gr2d_match,
0403         .pm = &tegra_gr2d_pm,
0404     },
0405     .probe = gr2d_probe,
0406     .remove = gr2d_remove,
0407 };