Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm: zte: add VGA driver support

It adds VGA driver support, which needs to configure corresponding VOU
interface in RGB_888 format, and thus the following changes are needed
on zx_vou.

- Rename the CSC block of Graphic Layer a bit to make it more specific,
and add CSC of Channel to support RGB output.
- Bypass Dither block for RGB output.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Link: http://patchwork.freedesktop.org/patch/msgid/1491910226-7831-1-git-send-email-shawnguo@kernel.org

+611 -4
+1
drivers/gpu/drm/zte/Makefile
··· 3 3 zx_hdmi.o \ 4 4 zx_plane.o \ 5 5 zx_tvenc.o \ 6 + zx_vga.o \ 6 7 zx_vou.o 7 8 8 9 obj-$(CONFIG_DRM_ZTE) += zxdrm.o
+1
drivers/gpu/drm/zte/zx_drm_drv.c
··· 233 233 &zx_crtc_driver, 234 234 &zx_hdmi_driver, 235 235 &zx_tvenc_driver, 236 + &zx_vga_driver, 236 237 &zx_drm_platform_driver, 237 238 }; 238 239
+1
drivers/gpu/drm/zte/zx_drm_drv.h
··· 14 14 extern struct platform_driver zx_crtc_driver; 15 15 extern struct platform_driver zx_hdmi_driver; 16 16 extern struct platform_driver zx_tvenc_driver; 17 + extern struct platform_driver zx_vga_driver; 17 18 18 19 static inline u32 zx_readl(void __iomem *reg) 19 20 {
+531
drivers/gpu/drm/zte/zx_vga.c
··· 1 + /* 2 + * Copyright (C) 2017 Sanechips Technology Co., Ltd. 3 + * Copyright 2017 Linaro Ltd. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + 10 + #include <linux/clk.h> 11 + #include <linux/component.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/regmap.h> 14 + 15 + #include <drm/drm_atomic_helper.h> 16 + #include <drm/drm_crtc_helper.h> 17 + #include <drm/drmP.h> 18 + 19 + #include "zx_drm_drv.h" 20 + #include "zx_vga_regs.h" 21 + #include "zx_vou.h" 22 + 23 + struct zx_vga_pwrctrl { 24 + struct regmap *regmap; 25 + u32 reg; 26 + u32 mask; 27 + }; 28 + 29 + struct zx_vga_i2c { 30 + struct i2c_adapter adap; 31 + struct mutex lock; 32 + }; 33 + 34 + struct zx_vga { 35 + struct drm_connector connector; 36 + struct drm_encoder encoder; 37 + struct zx_vga_i2c *ddc; 38 + struct device *dev; 39 + void __iomem *mmio; 40 + struct clk *i2c_wclk; 41 + struct zx_vga_pwrctrl pwrctrl; 42 + struct completion complete; 43 + bool connected; 44 + }; 45 + 46 + #define to_zx_vga(x) container_of(x, struct zx_vga, x) 47 + 48 + static void zx_vga_encoder_enable(struct drm_encoder *encoder) 49 + { 50 + struct zx_vga *vga = to_zx_vga(encoder); 51 + struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; 52 + 53 + /* Set bit to power up VGA DACs */ 54 + regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 55 + pwrctrl->mask); 56 + 57 + vou_inf_enable(VOU_VGA, encoder->crtc); 58 + } 59 + 60 + static void zx_vga_encoder_disable(struct drm_encoder *encoder) 61 + { 62 + struct zx_vga *vga = to_zx_vga(encoder); 63 + struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; 64 + 65 + vou_inf_disable(VOU_VGA, encoder->crtc); 66 + 67 + /* Clear bit to power down VGA DACs */ 68 + regmap_update_bits(pwrctrl->regmap, pwrctrl->reg, pwrctrl->mask, 0); 69 + } 70 + 71 + static const struct drm_encoder_helper_funcs zx_vga_encoder_helper_funcs = { 72 + .enable = zx_vga_encoder_enable, 73 + .disable = zx_vga_encoder_disable, 74 + }; 75 + 76 + static const struct drm_encoder_funcs zx_vga_encoder_funcs = { 77 + .destroy = drm_encoder_cleanup, 78 + }; 79 + 80 + static int zx_vga_connector_get_modes(struct drm_connector *connector) 81 + { 82 + struct zx_vga *vga = to_zx_vga(connector); 83 + struct edid *edid; 84 + int ret; 85 + 86 + /* 87 + * Clear both detection bits to switch I2C bus from device 88 + * detecting to EDID reading. 89 + */ 90 + zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, 0); 91 + 92 + edid = drm_get_edid(connector, &vga->ddc->adap); 93 + if (!edid) { 94 + /* 95 + * If EDID reading fails, we set the device state into 96 + * disconnected. Locking is not required here, since the 97 + * VGA_AUTO_DETECT_SEL register write in irq handler cannot 98 + * be triggered when both detection bits are cleared as above. 99 + */ 100 + zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, 101 + VGA_DETECT_SEL_NO_DEVICE); 102 + vga->connected = false; 103 + return 0; 104 + } 105 + 106 + /* 107 + * As edid reading succeeds, device must be connected, so we set 108 + * up detection bit for unplug interrupt here. 109 + */ 110 + zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_HAS_DEVICE); 111 + 112 + drm_mode_connector_update_edid_property(connector, edid); 113 + ret = drm_add_edid_modes(connector, edid); 114 + kfree(edid); 115 + 116 + return ret; 117 + } 118 + 119 + static enum drm_mode_status 120 + zx_vga_connector_mode_valid(struct drm_connector *connector, 121 + struct drm_display_mode *mode) 122 + { 123 + return MODE_OK; 124 + } 125 + 126 + static struct drm_connector_helper_funcs zx_vga_connector_helper_funcs = { 127 + .get_modes = zx_vga_connector_get_modes, 128 + .mode_valid = zx_vga_connector_mode_valid, 129 + }; 130 + 131 + static enum drm_connector_status 132 + zx_vga_connector_detect(struct drm_connector *connector, bool force) 133 + { 134 + struct zx_vga *vga = to_zx_vga(connector); 135 + 136 + return vga->connected ? connector_status_connected : 137 + connector_status_disconnected; 138 + } 139 + 140 + static const struct drm_connector_funcs zx_vga_connector_funcs = { 141 + .dpms = drm_atomic_helper_connector_dpms, 142 + .fill_modes = drm_helper_probe_single_connector_modes, 143 + .detect = zx_vga_connector_detect, 144 + .destroy = drm_connector_cleanup, 145 + .reset = drm_atomic_helper_connector_reset, 146 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 147 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 148 + }; 149 + 150 + static int zx_vga_register(struct drm_device *drm, struct zx_vga *vga) 151 + { 152 + struct drm_encoder *encoder = &vga->encoder; 153 + struct drm_connector *connector = &vga->connector; 154 + struct device *dev = vga->dev; 155 + int ret; 156 + 157 + encoder->possible_crtcs = VOU_CRTC_MASK; 158 + 159 + ret = drm_encoder_init(drm, encoder, &zx_vga_encoder_funcs, 160 + DRM_MODE_ENCODER_DAC, NULL); 161 + if (ret) { 162 + DRM_DEV_ERROR(dev, "failed to init encoder: %d\n", ret); 163 + return ret; 164 + }; 165 + 166 + drm_encoder_helper_add(encoder, &zx_vga_encoder_helper_funcs); 167 + 168 + vga->connector.polled = DRM_CONNECTOR_POLL_HPD; 169 + 170 + ret = drm_connector_init(drm, connector, &zx_vga_connector_funcs, 171 + DRM_MODE_CONNECTOR_VGA); 172 + if (ret) { 173 + DRM_DEV_ERROR(dev, "failed to init connector: %d\n", ret); 174 + goto clean_encoder; 175 + }; 176 + 177 + drm_connector_helper_add(connector, &zx_vga_connector_helper_funcs); 178 + 179 + ret = drm_mode_connector_attach_encoder(connector, encoder); 180 + if (ret) { 181 + DRM_DEV_ERROR(dev, "failed to attach encoder: %d\n", ret); 182 + goto clean_connector; 183 + }; 184 + 185 + return 0; 186 + 187 + clean_connector: 188 + drm_connector_cleanup(connector); 189 + clean_encoder: 190 + drm_encoder_cleanup(encoder); 191 + return ret; 192 + } 193 + 194 + static int zx_vga_pwrctrl_init(struct zx_vga *vga) 195 + { 196 + struct zx_vga_pwrctrl *pwrctrl = &vga->pwrctrl; 197 + struct device *dev = vga->dev; 198 + struct of_phandle_args out_args; 199 + struct regmap *regmap; 200 + int ret; 201 + 202 + ret = of_parse_phandle_with_fixed_args(dev->of_node, 203 + "zte,vga-power-control", 2, 0, &out_args); 204 + if (ret) 205 + return ret; 206 + 207 + regmap = syscon_node_to_regmap(out_args.np); 208 + if (IS_ERR(regmap)) { 209 + ret = PTR_ERR(regmap); 210 + goto out; 211 + } 212 + 213 + pwrctrl->regmap = regmap; 214 + pwrctrl->reg = out_args.args[0]; 215 + pwrctrl->mask = out_args.args[1]; 216 + 217 + out: 218 + of_node_put(out_args.np); 219 + return ret; 220 + } 221 + 222 + static int zx_vga_i2c_read(struct zx_vga *vga, struct i2c_msg *msg) 223 + { 224 + int len = msg->len; 225 + u8 *buf = msg->buf; 226 + u32 offset = 0; 227 + int i; 228 + 229 + reinit_completion(&vga->complete); 230 + 231 + /* Select combo write */ 232 + zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_COMBO, VGA_CMD_COMBO); 233 + zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_RW, 0); 234 + 235 + while (len > 0) { 236 + u32 cnt; 237 + 238 + /* Clear RX FIFO */ 239 + zx_writel_mask(vga->mmio + VGA_RXF_CTRL, VGA_RX_FIFO_CLEAR, 240 + VGA_RX_FIFO_CLEAR); 241 + 242 + /* Data offset to read from */ 243 + zx_writel(vga->mmio + VGA_SUB_ADDR, offset); 244 + 245 + /* Kick off the transfer */ 246 + zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_TRANS, 247 + VGA_CMD_TRANS); 248 + 249 + if (!wait_for_completion_timeout(&vga->complete, 250 + msecs_to_jiffies(1000))) { 251 + DRM_DEV_ERROR(vga->dev, "transfer timeout\n"); 252 + return -ETIMEDOUT; 253 + } 254 + 255 + cnt = zx_readl(vga->mmio + VGA_RXF_STATUS); 256 + cnt = (cnt & VGA_RXF_COUNT_MASK) >> VGA_RXF_COUNT_SHIFT; 257 + /* FIFO status may report more data than we need to read */ 258 + cnt = min_t(u32, len, cnt); 259 + 260 + for (i = 0; i < cnt; i++) 261 + *buf++ = zx_readl(vga->mmio + VGA_DATA); 262 + 263 + len -= cnt; 264 + offset += cnt; 265 + } 266 + 267 + return 0; 268 + } 269 + 270 + static int zx_vga_i2c_write(struct zx_vga *vga, struct i2c_msg *msg) 271 + { 272 + /* 273 + * The DDC I2C adapter is only for reading EDID data, so we assume 274 + * that the write to this adapter must be the EDID data offset. 275 + */ 276 + if ((msg->len != 1) || ((msg->addr != DDC_ADDR))) 277 + return -EINVAL; 278 + 279 + /* Hardware will take care of the slave address shifting */ 280 + zx_writel(vga->mmio + VGA_DEVICE_ADDR, msg->addr); 281 + 282 + return 0; 283 + } 284 + 285 + static int zx_vga_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, 286 + int num) 287 + { 288 + struct zx_vga *vga = i2c_get_adapdata(adap); 289 + struct zx_vga_i2c *ddc = vga->ddc; 290 + int ret = 0; 291 + int i; 292 + 293 + mutex_lock(&ddc->lock); 294 + 295 + for (i = 0; i < num; i++) { 296 + if (msgs[i].flags & I2C_M_RD) 297 + ret = zx_vga_i2c_read(vga, &msgs[i]); 298 + else 299 + ret = zx_vga_i2c_write(vga, &msgs[i]); 300 + 301 + if (ret < 0) 302 + break; 303 + } 304 + 305 + if (!ret) 306 + ret = num; 307 + 308 + mutex_unlock(&ddc->lock); 309 + 310 + return ret; 311 + } 312 + 313 + static u32 zx_vga_i2c_func(struct i2c_adapter *adapter) 314 + { 315 + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 316 + } 317 + 318 + static const struct i2c_algorithm zx_vga_algorithm = { 319 + .master_xfer = zx_vga_i2c_xfer, 320 + .functionality = zx_vga_i2c_func, 321 + }; 322 + 323 + static int zx_vga_ddc_register(struct zx_vga *vga) 324 + { 325 + struct device *dev = vga->dev; 326 + struct i2c_adapter *adap; 327 + struct zx_vga_i2c *ddc; 328 + int ret; 329 + 330 + ddc = devm_kzalloc(dev, sizeof(*ddc), GFP_KERNEL); 331 + if (!ddc) 332 + return -ENOMEM; 333 + 334 + vga->ddc = ddc; 335 + mutex_init(&ddc->lock); 336 + 337 + adap = &ddc->adap; 338 + adap->owner = THIS_MODULE; 339 + adap->class = I2C_CLASS_DDC; 340 + adap->dev.parent = dev; 341 + adap->algo = &zx_vga_algorithm; 342 + snprintf(adap->name, sizeof(adap->name), "zx vga i2c"); 343 + 344 + ret = i2c_add_adapter(adap); 345 + if (ret) { 346 + DRM_DEV_ERROR(dev, "failed to add I2C adapter: %d\n", ret); 347 + return ret; 348 + } 349 + 350 + i2c_set_adapdata(adap, vga); 351 + 352 + return 0; 353 + } 354 + 355 + static irqreturn_t zx_vga_irq_thread(int irq, void *dev_id) 356 + { 357 + struct zx_vga *vga = dev_id; 358 + 359 + drm_helper_hpd_irq_event(vga->connector.dev); 360 + 361 + return IRQ_HANDLED; 362 + } 363 + 364 + static irqreturn_t zx_vga_irq_handler(int irq, void *dev_id) 365 + { 366 + struct zx_vga *vga = dev_id; 367 + u32 status; 368 + 369 + status = zx_readl(vga->mmio + VGA_I2C_STATUS); 370 + 371 + /* Clear interrupt status */ 372 + zx_writel_mask(vga->mmio + VGA_I2C_STATUS, VGA_CLEAR_IRQ, 373 + VGA_CLEAR_IRQ); 374 + 375 + if (status & VGA_DEVICE_CONNECTED) { 376 + /* 377 + * Since VGA_DETECT_SEL bits need to be reset for switching DDC 378 + * bus from device detection to EDID read, rather than setting 379 + * up HAS_DEVICE bit here, we need to do that in .get_modes 380 + * hook for unplug detecting after EDID read succeeds. 381 + */ 382 + vga->connected = true; 383 + return IRQ_WAKE_THREAD; 384 + } 385 + 386 + if (status & VGA_DEVICE_DISCONNECTED) { 387 + zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, 388 + VGA_DETECT_SEL_NO_DEVICE); 389 + vga->connected = false; 390 + return IRQ_WAKE_THREAD; 391 + } 392 + 393 + if (status & VGA_TRANS_DONE) { 394 + complete(&vga->complete); 395 + return IRQ_HANDLED; 396 + } 397 + 398 + return IRQ_NONE; 399 + } 400 + 401 + static void zx_vga_hw_init(struct zx_vga *vga) 402 + { 403 + unsigned long ref = clk_get_rate(vga->i2c_wclk); 404 + int div; 405 + 406 + /* 407 + * Set up I2C fast speed divider per formula below to get 400kHz. 408 + * scl = ref / ((div + 1) * 4) 409 + */ 410 + div = DIV_ROUND_UP(ref / 1000, 400 * 4) - 1; 411 + zx_writel(vga->mmio + VGA_CLK_DIV_FS, div); 412 + 413 + /* Set up device detection */ 414 + zx_writel(vga->mmio + VGA_AUTO_DETECT_PARA, 0x80); 415 + zx_writel(vga->mmio + VGA_AUTO_DETECT_SEL, VGA_DETECT_SEL_NO_DEVICE); 416 + 417 + /* 418 + * We need to poke monitor via DDC bus to get connection irq 419 + * start working. 420 + */ 421 + zx_writel(vga->mmio + VGA_DEVICE_ADDR, DDC_ADDR); 422 + zx_writel_mask(vga->mmio + VGA_CMD_CFG, VGA_CMD_TRANS, VGA_CMD_TRANS); 423 + } 424 + 425 + static int zx_vga_bind(struct device *dev, struct device *master, void *data) 426 + { 427 + struct platform_device *pdev = to_platform_device(dev); 428 + struct drm_device *drm = data; 429 + struct resource *res; 430 + struct zx_vga *vga; 431 + int irq; 432 + int ret; 433 + 434 + vga = devm_kzalloc(dev, sizeof(*vga), GFP_KERNEL); 435 + if (!vga) 436 + return -ENOMEM; 437 + 438 + vga->dev = dev; 439 + dev_set_drvdata(dev, vga); 440 + 441 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 442 + vga->mmio = devm_ioremap_resource(dev, res); 443 + if (IS_ERR(vga->mmio)) 444 + return PTR_ERR(vga->mmio); 445 + 446 + irq = platform_get_irq(pdev, 0); 447 + if (irq < 0) 448 + return irq; 449 + 450 + vga->i2c_wclk = devm_clk_get(dev, "i2c_wclk"); 451 + if (IS_ERR(vga->i2c_wclk)) { 452 + ret = PTR_ERR(vga->i2c_wclk); 453 + DRM_DEV_ERROR(dev, "failed to get i2c_wclk: %d\n", ret); 454 + return ret; 455 + } 456 + 457 + ret = zx_vga_pwrctrl_init(vga); 458 + if (ret) { 459 + DRM_DEV_ERROR(dev, "failed to init power control: %d\n", ret); 460 + return ret; 461 + } 462 + 463 + ret = zx_vga_ddc_register(vga); 464 + if (ret) { 465 + DRM_DEV_ERROR(dev, "failed to register ddc: %d\n", ret); 466 + return ret; 467 + } 468 + 469 + ret = zx_vga_register(drm, vga); 470 + if (ret) { 471 + DRM_DEV_ERROR(dev, "failed to register vga: %d\n", ret); 472 + return ret; 473 + } 474 + 475 + init_completion(&vga->complete); 476 + 477 + ret = devm_request_threaded_irq(dev, irq, zx_vga_irq_handler, 478 + zx_vga_irq_thread, IRQF_SHARED, 479 + dev_name(dev), vga); 480 + if (ret) { 481 + DRM_DEV_ERROR(dev, "failed to request threaded irq: %d\n", ret); 482 + return ret; 483 + } 484 + 485 + ret = clk_prepare_enable(vga->i2c_wclk); 486 + if (ret) 487 + return ret; 488 + 489 + zx_vga_hw_init(vga); 490 + 491 + return 0; 492 + } 493 + 494 + static void zx_vga_unbind(struct device *dev, struct device *master, 495 + void *data) 496 + { 497 + struct zx_vga *vga = dev_get_drvdata(dev); 498 + 499 + clk_disable_unprepare(vga->i2c_wclk); 500 + } 501 + 502 + static const struct component_ops zx_vga_component_ops = { 503 + .bind = zx_vga_bind, 504 + .unbind = zx_vga_unbind, 505 + }; 506 + 507 + static int zx_vga_probe(struct platform_device *pdev) 508 + { 509 + return component_add(&pdev->dev, &zx_vga_component_ops); 510 + } 511 + 512 + static int zx_vga_remove(struct platform_device *pdev) 513 + { 514 + component_del(&pdev->dev, &zx_vga_component_ops); 515 + return 0; 516 + } 517 + 518 + static const struct of_device_id zx_vga_of_match[] = { 519 + { .compatible = "zte,zx296718-vga", }, 520 + { /* end */ }, 521 + }; 522 + MODULE_DEVICE_TABLE(of, zx_vga_of_match); 523 + 524 + struct platform_driver zx_vga_driver = { 525 + .probe = zx_vga_probe, 526 + .remove = zx_vga_remove, 527 + .driver = { 528 + .name = "zx-vga", 529 + .of_match_table = zx_vga_of_match, 530 + }, 531 + };
+36
drivers/gpu/drm/zte/zx_vga_regs.h
··· 1 + /* 2 + * Copyright (C) 2017 Sanechips Technology Co., Ltd. 3 + * Copyright 2017 Linaro Ltd. 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + */ 9 + 10 + #ifndef __ZX_VGA_REGS_H__ 11 + #define __ZX_VGA_REGS_H__ 12 + 13 + #define VGA_CMD_CFG 0x04 14 + #define VGA_CMD_TRANS BIT(6) 15 + #define VGA_CMD_COMBO BIT(5) 16 + #define VGA_CMD_RW BIT(4) 17 + #define VGA_SUB_ADDR 0x0c 18 + #define VGA_DEVICE_ADDR 0x10 19 + #define VGA_CLK_DIV_FS 0x14 20 + #define VGA_RXF_CTRL 0x20 21 + #define VGA_RX_FIFO_CLEAR BIT(7) 22 + #define VGA_DATA 0x24 23 + #define VGA_I2C_STATUS 0x28 24 + #define VGA_DEVICE_DISCONNECTED BIT(7) 25 + #define VGA_DEVICE_CONNECTED BIT(6) 26 + #define VGA_CLEAR_IRQ BIT(4) 27 + #define VGA_TRANS_DONE BIT(0) 28 + #define VGA_RXF_STATUS 0x30 29 + #define VGA_RXF_COUNT_SHIFT 2 30 + #define VGA_RXF_COUNT_MASK GENMASK(7, 2) 31 + #define VGA_AUTO_DETECT_PARA 0x34 32 + #define VGA_AUTO_DETECT_SEL 0x38 33 + #define VGA_DETECT_SEL_HAS_DEVICE BIT(1) 34 + #define VGA_DETECT_SEL_NO_DEVICE BIT(0) 35 + 36 + #endif /* __ZX_VGA_REGS_H__ */
+31 -2
drivers/gpu/drm/zte/zx_vou.c
··· 23 23 #include <drm/drm_plane_helper.h> 24 24 #include <drm/drmP.h> 25 25 26 + #include "zx_common_regs.h" 26 27 #include "zx_drm_drv.h" 27 28 #include "zx_plane.h" 28 29 #include "zx_vou.h" ··· 123 122 struct drm_plane *primary; 124 123 struct zx_vou_hw *vou; 125 124 void __iomem *chnreg; 125 + void __iomem *chncsc; 126 + void __iomem *dither; 126 127 const struct zx_crtc_regs *regs; 127 128 const struct zx_crtc_bits *bits; 128 129 enum vou_chn_type chn_type; ··· 207 204 .clocks_en_bits = BIT(15), 208 205 .clocks_sel_bits = BIT(11) | BIT(0), 209 206 }, 207 + [VOU_VGA] = { 208 + .data_sel = VOU_RGB_888, 209 + .clocks_en_bits = BIT(1), 210 + .clocks_sel_bits = BIT(10), 211 + }, 210 212 }; 211 213 212 214 static inline struct zx_vou_hw *crtc_to_vou(struct drm_crtc *crtc) ··· 235 227 struct zx_crtc *zcrtc = to_zx_crtc(crtc); 236 228 struct zx_vou_hw *vou = zcrtc->vou; 237 229 struct vou_inf *inf = &vou_infs[id]; 230 + void __iomem *dither = zcrtc->dither; 231 + void __iomem *csc = zcrtc->chncsc; 238 232 bool is_main = zcrtc->chn_type == VOU_CHN_MAIN; 239 233 u32 data_sel_shift = id << 1; 234 + 235 + if (inf->data_sel != VOU_YUV444) { 236 + /* Enable channel CSC for RGB output */ 237 + zx_writel_mask(csc + CSC_CTRL0, CSC_COV_MODE_MASK, 238 + CSC_BT709_IMAGE_YCBCR2RGB << CSC_COV_MODE_SHIFT); 239 + zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, 240 + CSC_WORK_ENABLE); 241 + 242 + /* Bypass Dither block for RGB output */ 243 + zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS, 244 + DITHER_BYSPASS); 245 + } else { 246 + zx_writel_mask(csc + CSC_CTRL0, CSC_WORK_ENABLE, 0); 247 + zx_writel_mask(dither + OSD_DITHER_CTRL0, DITHER_BYSPASS, 0); 248 + } 240 249 241 250 /* Select data format */ 242 251 zx_writel_mask(vou->vouctl + VOU_INF_DATA_SEL, 0x3 << data_sel_shift, ··· 550 525 551 526 if (chn_type == VOU_CHN_MAIN) { 552 527 zplane->layer = vou->osd + MAIN_GL_OFFSET; 553 - zplane->csc = vou->osd + MAIN_CSC_OFFSET; 528 + zplane->csc = vou->osd + MAIN_GL_CSC_OFFSET; 554 529 zplane->hbsc = vou->osd + MAIN_HBSC_OFFSET; 555 530 zplane->rsz = vou->otfppu + MAIN_RSZ_OFFSET; 556 531 zplane->bits = &zx_gl_bits[0]; 557 532 zcrtc->chnreg = vou->osd + OSD_MAIN_CHN; 533 + zcrtc->chncsc = vou->osd + MAIN_CHN_CSC_OFFSET; 534 + zcrtc->dither = vou->osd + MAIN_DITHER_OFFSET; 558 535 zcrtc->regs = &main_crtc_regs; 559 536 zcrtc->bits = &main_crtc_bits; 560 537 } else { 561 538 zplane->layer = vou->osd + AUX_GL_OFFSET; 562 - zplane->csc = vou->osd + AUX_CSC_OFFSET; 539 + zplane->csc = vou->osd + AUX_GL_CSC_OFFSET; 563 540 zplane->hbsc = vou->osd + AUX_HBSC_OFFSET; 564 541 zplane->rsz = vou->otfppu + AUX_RSZ_OFFSET; 565 542 zplane->bits = &zx_gl_bits[1]; 566 543 zcrtc->chnreg = vou->osd + OSD_AUX_CHN; 544 + zcrtc->chncsc = vou->osd + AUX_CHN_CSC_OFFSET; 545 + zcrtc->dither = vou->osd + AUX_DITHER_OFFSET; 567 546 zcrtc->regs = &aux_crtc_regs; 568 547 zcrtc->bits = &aux_crtc_bits; 569 548 }
+10 -2
drivers/gpu/drm/zte/zx_vou_regs.h
··· 13 13 14 14 /* Sub-module offset */ 15 15 #define MAIN_GL_OFFSET 0x130 16 - #define MAIN_CSC_OFFSET 0x580 16 + #define MAIN_GL_CSC_OFFSET 0x580 17 + #define MAIN_CHN_CSC_OFFSET 0x6c0 17 18 #define MAIN_HBSC_OFFSET 0x820 19 + #define MAIN_DITHER_OFFSET 0x960 18 20 #define MAIN_RSZ_OFFSET 0x600 /* OTFPPU sub-module */ 19 21 20 22 #define AUX_GL_OFFSET 0x200 21 - #define AUX_CSC_OFFSET 0x5d0 23 + #define AUX_GL_CSC_OFFSET 0x5d0 24 + #define AUX_CHN_CSC_OFFSET 0x710 22 25 #define AUX_HBSC_OFFSET 0x860 26 + #define AUX_DITHER_OFFSET 0x970 23 27 #define AUX_RSZ_OFFSET 0x800 24 28 25 29 #define OSD_VL0_OFFSET 0x040 ··· 81 77 #define CHN_UPDATE 0x08 82 78 #define CHN_INTERLACE_BUF_CTRL 0x24 83 79 #define CHN_INTERLACE_EN BIT(2) 80 + 81 + /* Dither registers */ 82 + #define OSD_DITHER_CTRL0 0x00 83 + #define DITHER_BYSPASS BIT(31) 84 84 85 85 /* TIMING_CTRL registers */ 86 86 #define TIMING_TC_ENABLE 0x04