0001
0002
0003
0004 #include <linux/clk.h>
0005 #include <linux/dma-mapping.h>
0006 #include <linux/irq.h>
0007 #include <linux/mfd/syscon.h>
0008 #include <linux/module.h>
0009 #include <linux/of.h>
0010 #include <linux/of_device.h>
0011 #include <linux/of_reserved_mem.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/regmap.h>
0014 #include <linux/reset.h>
0015
0016 #include <drm/drm_atomic_helper.h>
0017 #include <drm/drm_crtc_helper.h>
0018 #include <drm/drm_device.h>
0019 #include <drm/drm_fb_cma_helper.h>
0020 #include <drm/drm_fb_helper.h>
0021 #include <drm/drm_gem_cma_helper.h>
0022 #include <drm/drm_gem_framebuffer_helper.h>
0023 #include <drm/drm_module.h>
0024 #include <drm/drm_probe_helper.h>
0025 #include <drm/drm_simple_kms_helper.h>
0026 #include <drm/drm_vblank.h>
0027 #include <drm/drm_drv.h>
0028
0029 #include "aspeed_gfx.h"
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 struct aspeed_gfx_config {
0063 u32 dac_reg;
0064 u32 int_clear_reg;
0065 u32 vga_scratch_reg;
0066 u32 throd_val;
0067 u32 scan_line_max;
0068 };
0069
0070 static const struct aspeed_gfx_config ast2400_config = {
0071 .dac_reg = 0x2c,
0072 .int_clear_reg = 0x60,
0073 .vga_scratch_reg = 0x50,
0074 .throd_val = CRT_THROD_LOW(0x1e) | CRT_THROD_HIGH(0x12),
0075 .scan_line_max = 64,
0076 };
0077
0078 static const struct aspeed_gfx_config ast2500_config = {
0079 .dac_reg = 0x2c,
0080 .int_clear_reg = 0x60,
0081 .vga_scratch_reg = 0x50,
0082 .throd_val = CRT_THROD_LOW(0x24) | CRT_THROD_HIGH(0x3c),
0083 .scan_line_max = 128,
0084 };
0085
0086 static const struct aspeed_gfx_config ast2600_config = {
0087 .dac_reg = 0xc0,
0088 .int_clear_reg = 0x68,
0089 .vga_scratch_reg = 0x50,
0090 .throd_val = CRT_THROD_LOW(0x50) | CRT_THROD_HIGH(0x70),
0091 .scan_line_max = 128,
0092 };
0093
0094 static const struct of_device_id aspeed_gfx_match[] = {
0095 { .compatible = "aspeed,ast2400-gfx", .data = &ast2400_config },
0096 { .compatible = "aspeed,ast2500-gfx", .data = &ast2500_config },
0097 { .compatible = "aspeed,ast2600-gfx", .data = &ast2600_config },
0098 { },
0099 };
0100 MODULE_DEVICE_TABLE(of, aspeed_gfx_match);
0101
0102 static const struct drm_mode_config_funcs aspeed_gfx_mode_config_funcs = {
0103 .fb_create = drm_gem_fb_create,
0104 .atomic_check = drm_atomic_helper_check,
0105 .atomic_commit = drm_atomic_helper_commit,
0106 };
0107
0108 static int aspeed_gfx_setup_mode_config(struct drm_device *drm)
0109 {
0110 int ret;
0111
0112 ret = drmm_mode_config_init(drm);
0113 if (ret)
0114 return ret;
0115
0116 drm->mode_config.min_width = 0;
0117 drm->mode_config.min_height = 0;
0118 drm->mode_config.max_width = 800;
0119 drm->mode_config.max_height = 600;
0120 drm->mode_config.funcs = &aspeed_gfx_mode_config_funcs;
0121
0122 return ret;
0123 }
0124
0125 static irqreturn_t aspeed_gfx_irq_handler(int irq, void *data)
0126 {
0127 struct drm_device *drm = data;
0128 struct aspeed_gfx *priv = to_aspeed_gfx(drm);
0129 u32 reg;
0130
0131 reg = readl(priv->base + CRT_CTRL1);
0132
0133 if (reg & CRT_CTRL_VERTICAL_INTR_STS) {
0134 drm_crtc_handle_vblank(&priv->pipe.crtc);
0135 writel(reg, priv->base + priv->int_clr_reg);
0136 return IRQ_HANDLED;
0137 }
0138
0139 return IRQ_NONE;
0140 }
0141
0142 static int aspeed_gfx_load(struct drm_device *drm)
0143 {
0144 struct platform_device *pdev = to_platform_device(drm->dev);
0145 struct aspeed_gfx *priv = to_aspeed_gfx(drm);
0146 struct device_node *np = pdev->dev.of_node;
0147 const struct aspeed_gfx_config *config;
0148 const struct of_device_id *match;
0149 struct resource *res;
0150 int ret;
0151
0152 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0153 priv->base = devm_ioremap_resource(drm->dev, res);
0154 if (IS_ERR(priv->base))
0155 return PTR_ERR(priv->base);
0156
0157 match = of_match_device(aspeed_gfx_match, &pdev->dev);
0158 if (!match)
0159 return -EINVAL;
0160 config = match->data;
0161
0162 priv->dac_reg = config->dac_reg;
0163 priv->int_clr_reg = config->int_clear_reg;
0164 priv->vga_scratch_reg = config->vga_scratch_reg;
0165 priv->throd_val = config->throd_val;
0166 priv->scan_line_max = config->scan_line_max;
0167
0168 priv->scu = syscon_regmap_lookup_by_phandle(np, "syscon");
0169 if (IS_ERR(priv->scu)) {
0170 priv->scu = syscon_regmap_lookup_by_compatible("aspeed,ast2500-scu");
0171 if (IS_ERR(priv->scu)) {
0172 dev_err(&pdev->dev, "failed to find SCU regmap\n");
0173 return PTR_ERR(priv->scu);
0174 }
0175 }
0176
0177 ret = of_reserved_mem_device_init(drm->dev);
0178 if (ret) {
0179 dev_err(&pdev->dev,
0180 "failed to initialize reserved mem: %d\n", ret);
0181 return ret;
0182 }
0183
0184 ret = dma_set_mask_and_coherent(drm->dev, DMA_BIT_MASK(32));
0185 if (ret) {
0186 dev_err(&pdev->dev, "failed to set DMA mask: %d\n", ret);
0187 return ret;
0188 }
0189
0190 priv->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
0191 if (IS_ERR(priv->rst)) {
0192 dev_err(&pdev->dev,
0193 "missing or invalid reset controller device tree entry");
0194 return PTR_ERR(priv->rst);
0195 }
0196 reset_control_deassert(priv->rst);
0197
0198 priv->clk = devm_clk_get(drm->dev, NULL);
0199 if (IS_ERR(priv->clk)) {
0200 dev_err(&pdev->dev,
0201 "missing or invalid clk device tree entry");
0202 return PTR_ERR(priv->clk);
0203 }
0204 clk_prepare_enable(priv->clk);
0205
0206
0207 writel(0, priv->base + CRT_CTRL1);
0208 writel(0, priv->base + CRT_CTRL2);
0209
0210 ret = aspeed_gfx_setup_mode_config(drm);
0211 if (ret < 0)
0212 return ret;
0213
0214 ret = drm_vblank_init(drm, 1);
0215 if (ret < 0) {
0216 dev_err(drm->dev, "Failed to initialise vblank\n");
0217 return ret;
0218 }
0219
0220 ret = aspeed_gfx_create_output(drm);
0221 if (ret < 0) {
0222 dev_err(drm->dev, "Failed to create outputs\n");
0223 return ret;
0224 }
0225
0226 ret = aspeed_gfx_create_pipe(drm);
0227 if (ret < 0) {
0228 dev_err(drm->dev, "Cannot setup simple display pipe\n");
0229 return ret;
0230 }
0231
0232 ret = devm_request_irq(drm->dev, platform_get_irq(pdev, 0),
0233 aspeed_gfx_irq_handler, 0, "aspeed gfx", drm);
0234 if (ret < 0) {
0235 dev_err(drm->dev, "Failed to install IRQ handler\n");
0236 return ret;
0237 }
0238
0239 drm_mode_config_reset(drm);
0240
0241 return 0;
0242 }
0243
0244 static void aspeed_gfx_unload(struct drm_device *drm)
0245 {
0246 drm_kms_helper_poll_fini(drm);
0247 }
0248
0249 DEFINE_DRM_GEM_CMA_FOPS(fops);
0250
0251 static const struct drm_driver aspeed_gfx_driver = {
0252 .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
0253 DRM_GEM_CMA_DRIVER_OPS,
0254 .fops = &fops,
0255 .name = "aspeed-gfx-drm",
0256 .desc = "ASPEED GFX DRM",
0257 .date = "20180319",
0258 .major = 1,
0259 .minor = 0,
0260 };
0261
0262 static ssize_t dac_mux_store(struct device *dev, struct device_attribute *attr,
0263 const char *buf, size_t count)
0264 {
0265 struct aspeed_gfx *priv = dev_get_drvdata(dev);
0266 u32 val;
0267 int rc;
0268
0269 rc = kstrtou32(buf, 0, &val);
0270 if (rc)
0271 return rc;
0272
0273 if (val > 3)
0274 return -EINVAL;
0275
0276 rc = regmap_update_bits(priv->scu, priv->dac_reg, 0x30000, val << 16);
0277 if (rc < 0)
0278 return 0;
0279
0280 return count;
0281 }
0282
0283 static ssize_t dac_mux_show(struct device *dev, struct device_attribute *attr, char *buf)
0284 {
0285 struct aspeed_gfx *priv = dev_get_drvdata(dev);
0286 u32 reg;
0287 int rc;
0288
0289 rc = regmap_read(priv->scu, priv->dac_reg, ®);
0290 if (rc)
0291 return rc;
0292
0293 return sprintf(buf, "%u\n", (reg >> 16) & 0x3);
0294 }
0295 static DEVICE_ATTR_RW(dac_mux);
0296
0297 static ssize_t
0298 vga_pw_show(struct device *dev, struct device_attribute *attr, char *buf)
0299 {
0300 struct aspeed_gfx *priv = dev_get_drvdata(dev);
0301 u32 reg;
0302 int rc;
0303
0304 rc = regmap_read(priv->scu, priv->vga_scratch_reg, ®);
0305 if (rc)
0306 return rc;
0307
0308 return sprintf(buf, "%u\n", reg);
0309 }
0310 static DEVICE_ATTR_RO(vga_pw);
0311
0312 static struct attribute *aspeed_sysfs_entries[] = {
0313 &dev_attr_vga_pw.attr,
0314 &dev_attr_dac_mux.attr,
0315 NULL,
0316 };
0317
0318 static struct attribute_group aspeed_sysfs_attr_group = {
0319 .attrs = aspeed_sysfs_entries,
0320 };
0321
0322 static int aspeed_gfx_probe(struct platform_device *pdev)
0323 {
0324 struct aspeed_gfx *priv;
0325 int ret;
0326
0327 priv = devm_drm_dev_alloc(&pdev->dev, &aspeed_gfx_driver,
0328 struct aspeed_gfx, drm);
0329 if (IS_ERR(priv))
0330 return PTR_ERR(priv);
0331
0332 ret = aspeed_gfx_load(&priv->drm);
0333 if (ret)
0334 return ret;
0335
0336 platform_set_drvdata(pdev, priv);
0337
0338 ret = sysfs_create_group(&pdev->dev.kobj, &aspeed_sysfs_attr_group);
0339 if (ret)
0340 return ret;
0341
0342 ret = drm_dev_register(&priv->drm, 0);
0343 if (ret)
0344 goto err_unload;
0345
0346 drm_fbdev_generic_setup(&priv->drm, 32);
0347 return 0;
0348
0349 err_unload:
0350 sysfs_remove_group(&pdev->dev.kobj, &aspeed_sysfs_attr_group);
0351 aspeed_gfx_unload(&priv->drm);
0352
0353 return ret;
0354 }
0355
0356 static int aspeed_gfx_remove(struct platform_device *pdev)
0357 {
0358 struct drm_device *drm = platform_get_drvdata(pdev);
0359
0360 sysfs_remove_group(&pdev->dev.kobj, &aspeed_sysfs_attr_group);
0361 drm_dev_unregister(drm);
0362 aspeed_gfx_unload(drm);
0363
0364 return 0;
0365 }
0366
0367 static struct platform_driver aspeed_gfx_platform_driver = {
0368 .probe = aspeed_gfx_probe,
0369 .remove = aspeed_gfx_remove,
0370 .driver = {
0371 .name = "aspeed_gfx",
0372 .of_match_table = aspeed_gfx_match,
0373 },
0374 };
0375
0376 drm_module_platform_driver(aspeed_gfx_platform_driver);
0377
0378 MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
0379 MODULE_DESCRIPTION("ASPEED BMC DRM/KMS driver");
0380 MODULE_LICENSE("GPL");