1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Vincent Abriou <vincent.abriou@st.com> 6 * for STMicroelectronics. 7 * License terms: GNU General Public License (GPL), version 2 8 */ 9 10 #include <linux/module.h> 11 #include <linux/notifier.h> 12 #include <linux/platform_device.h> 13 14 #include <drm/drmP.h> 15 16 #include "sti_vtg.h" 17 18 #define VTG_TYPE_MASTER 0 19 #define VTG_TYPE_SLAVE_BY_EXT0 1 20 21 /* registers offset */ 22 #define VTG_MODE 0x0000 23 #define VTG_CLKLN 0x0008 24 #define VTG_HLFLN 0x000C 25 #define VTG_DRST_AUTOC 0x0010 26 #define VTG_VID_TFO 0x0040 27 #define VTG_VID_TFS 0x0044 28 #define VTG_VID_BFO 0x0048 29 #define VTG_VID_BFS 0x004C 30 31 #define VTG_HOST_ITS 0x0078 32 #define VTG_HOST_ITS_BCLR 0x007C 33 #define VTG_HOST_ITM_BCLR 0x0088 34 #define VTG_HOST_ITM_BSET 0x008C 35 36 #define VTG_H_HD_1 0x00C0 37 #define VTG_TOP_V_VD_1 0x00C4 38 #define VTG_BOT_V_VD_1 0x00C8 39 #define VTG_TOP_V_HD_1 0x00CC 40 #define VTG_BOT_V_HD_1 0x00D0 41 42 #define VTG_H_HD_2 0x00E0 43 #define VTG_TOP_V_VD_2 0x00E4 44 #define VTG_BOT_V_VD_2 0x00E8 45 #define VTG_TOP_V_HD_2 0x00EC 46 #define VTG_BOT_V_HD_2 0x00F0 47 48 #define VTG_H_HD_3 0x0100 49 #define VTG_TOP_V_VD_3 0x0104 50 #define VTG_BOT_V_VD_3 0x0108 51 #define VTG_TOP_V_HD_3 0x010C 52 #define VTG_BOT_V_HD_3 0x0110 53 54 #define VTG_H_HD_4 0x0120 55 #define VTG_TOP_V_VD_4 0x0124 56 #define VTG_BOT_V_VD_4 0x0128 57 #define VTG_TOP_V_HD_4 0x012c 58 #define VTG_BOT_V_HD_4 0x0130 59 60 #define VTG_IRQ_BOTTOM BIT(0) 61 #define VTG_IRQ_TOP BIT(1) 62 #define VTG_IRQ_MASK (VTG_IRQ_TOP | VTG_IRQ_BOTTOM) 63 64 /* Delay introduced by the HDMI in nb of pixel */ 65 #define HDMI_DELAY (5) 66 67 /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ 68 #define AWG_DELAY_HD (-9) 69 #define AWG_DELAY_ED (-8) 70 #define AWG_DELAY_SD (-7) 71 72 LIST_HEAD(vtg_lookup); 73 74 /** 75 * STI VTG structure 76 * 77 * @dev: pointer to device driver 78 * @data: data associated to the device 79 * @irq: VTG irq 80 * @type: VTG type (main or aux) 81 * @notifier_list: notifier callback 82 * @crtc_id: the crtc id for vblank event 83 * @slave: slave vtg 84 * @link: List node to link the structure in lookup list 85 */ 86 struct sti_vtg { 87 struct device *dev; 88 struct device_node *np; 89 void __iomem *regs; 90 int irq; 91 u32 irq_status; 92 struct raw_notifier_head notifier_list; 93 int crtc_id; 94 struct sti_vtg *slave; 95 struct list_head link; 96 }; 97 98 static void vtg_register(struct sti_vtg *vtg) 99 { 100 list_add_tail(&vtg->link, &vtg_lookup); 101 } 102 103 struct sti_vtg *of_vtg_find(struct device_node *np) 104 { 105 struct sti_vtg *vtg; 106 107 list_for_each_entry(vtg, &vtg_lookup, link) { 108 if (vtg->np == np) 109 return vtg; 110 } 111 return NULL; 112 } 113 EXPORT_SYMBOL(of_vtg_find); 114 115 static void vtg_reset(struct sti_vtg *vtg) 116 { 117 /* reset slave and then master */ 118 if (vtg->slave) 119 vtg_reset(vtg->slave); 120 121 writel(1, vtg->regs + VTG_DRST_AUTOC); 122 } 123 124 static void vtg_set_output_window(void __iomem *regs, 125 const struct drm_display_mode *mode) 126 { 127 u32 video_top_field_start; 128 u32 video_top_field_stop; 129 u32 video_bottom_field_start; 130 u32 video_bottom_field_stop; 131 u32 xstart = sti_vtg_get_pixel_number(*mode, 0); 132 u32 ystart = sti_vtg_get_line_number(*mode, 0); 133 u32 xstop = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); 134 u32 ystop = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); 135 136 /* Set output window to fit the display mode selected */ 137 video_top_field_start = (ystart << 16) | xstart; 138 video_top_field_stop = (ystop << 16) | xstop; 139 140 /* Only progressive supported for now */ 141 video_bottom_field_start = video_top_field_start; 142 video_bottom_field_stop = video_top_field_stop; 143 144 writel(video_top_field_start, regs + VTG_VID_TFO); 145 writel(video_top_field_stop, regs + VTG_VID_TFS); 146 writel(video_bottom_field_start, regs + VTG_VID_BFO); 147 writel(video_bottom_field_stop, regs + VTG_VID_BFS); 148 } 149 150 static void vtg_set_mode(struct sti_vtg *vtg, 151 int type, const struct drm_display_mode *mode) 152 { 153 u32 tmp; 154 155 if (vtg->slave) 156 vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); 157 158 /* Set the number of clock cycles per line */ 159 writel(mode->htotal, vtg->regs + VTG_CLKLN); 160 161 /* Set Half Line Per Field (only progressive supported for now) */ 162 writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN); 163 164 /* Program output window */ 165 vtg_set_output_window(vtg->regs, mode); 166 167 /* prepare VTG set 1 for HDMI */ 168 tmp = (mode->hsync_end - mode->hsync_start + HDMI_DELAY) << 16; 169 tmp |= HDMI_DELAY; 170 writel(tmp, vtg->regs + VTG_H_HD_1); 171 172 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 173 tmp |= 1; 174 writel(tmp, vtg->regs + VTG_TOP_V_VD_1); 175 writel(tmp, vtg->regs + VTG_BOT_V_VD_1); 176 writel(0, vtg->regs + VTG_TOP_V_HD_1); 177 writel(0, vtg->regs + VTG_BOT_V_HD_1); 178 179 /* prepare VTG set 2 for for HD DCS */ 180 tmp = (mode->hsync_end - mode->hsync_start) << 16; 181 writel(tmp, vtg->regs + VTG_H_HD_2); 182 183 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 184 tmp |= 1; 185 writel(tmp, vtg->regs + VTG_TOP_V_VD_2); 186 writel(tmp, vtg->regs + VTG_BOT_V_VD_2); 187 writel(0, vtg->regs + VTG_TOP_V_HD_2); 188 writel(0, vtg->regs + VTG_BOT_V_HD_2); 189 190 /* prepare VTG set 3 for HD Analog in HD mode */ 191 tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16; 192 tmp |= mode->htotal + AWG_DELAY_HD; 193 writel(tmp, vtg->regs + VTG_H_HD_3); 194 195 tmp = (mode->vsync_end - mode->vsync_start) << 16; 196 tmp |= mode->vtotal; 197 writel(tmp, vtg->regs + VTG_TOP_V_VD_3); 198 writel(tmp, vtg->regs + VTG_BOT_V_VD_3); 199 200 tmp = (mode->htotal + AWG_DELAY_HD) << 16; 201 tmp |= mode->htotal + AWG_DELAY_HD; 202 writel(tmp, vtg->regs + VTG_TOP_V_HD_3); 203 writel(tmp, vtg->regs + VTG_BOT_V_HD_3); 204 205 /* Prepare VTG set 4 for DVO */ 206 tmp = (mode->hsync_end - mode->hsync_start) << 16; 207 writel(tmp, vtg->regs + VTG_H_HD_4); 208 209 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 210 tmp |= 1; 211 writel(tmp, vtg->regs + VTG_TOP_V_VD_4); 212 writel(tmp, vtg->regs + VTG_BOT_V_VD_4); 213 writel(0, vtg->regs + VTG_TOP_V_HD_4); 214 writel(0, vtg->regs + VTG_BOT_V_HD_4); 215 216 /* mode */ 217 writel(type, vtg->regs + VTG_MODE); 218 } 219 220 static void vtg_enable_irq(struct sti_vtg *vtg) 221 { 222 /* clear interrupt status and mask */ 223 writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR); 224 writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR); 225 writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET); 226 } 227 228 void sti_vtg_set_config(struct sti_vtg *vtg, 229 const struct drm_display_mode *mode) 230 { 231 /* write configuration */ 232 vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); 233 234 vtg_reset(vtg); 235 236 /* enable irq for the vtg vblank synchro */ 237 if (vtg->slave) 238 vtg_enable_irq(vtg->slave); 239 else 240 vtg_enable_irq(vtg); 241 } 242 EXPORT_SYMBOL(sti_vtg_set_config); 243 244 /** 245 * sti_vtg_get_line_number 246 * 247 * @mode: display mode to be used 248 * @y: line 249 * 250 * Return the line number according to the display mode taking 251 * into account the Sync and Back Porch information. 252 * Video frame line numbers start at 1, y starts at 0. 253 * In interlaced modes the start line is the field line number of the odd 254 * field, but y is still defined as a progressive frame. 255 */ 256 u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) 257 { 258 u32 start_line = mode.vtotal - mode.vsync_start + 1; 259 260 if (mode.flags & DRM_MODE_FLAG_INTERLACE) 261 start_line *= 2; 262 263 return start_line + y; 264 } 265 EXPORT_SYMBOL(sti_vtg_get_line_number); 266 267 /** 268 * sti_vtg_get_pixel_number 269 * 270 * @mode: display mode to be used 271 * @x: row 272 * 273 * Return the pixel number according to the display mode taking 274 * into account the Sync and Back Porch information. 275 * Pixels are counted from 0. 276 */ 277 u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) 278 { 279 return mode.htotal - mode.hsync_start + x; 280 } 281 EXPORT_SYMBOL(sti_vtg_get_pixel_number); 282 283 int sti_vtg_register_client(struct sti_vtg *vtg, 284 struct notifier_block *nb, int crtc_id) 285 { 286 if (vtg->slave) 287 return sti_vtg_register_client(vtg->slave, nb, crtc_id); 288 289 vtg->crtc_id = crtc_id; 290 return raw_notifier_chain_register(&vtg->notifier_list, nb); 291 } 292 EXPORT_SYMBOL(sti_vtg_register_client); 293 294 int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) 295 { 296 if (vtg->slave) 297 return sti_vtg_unregister_client(vtg->slave, nb); 298 299 return raw_notifier_chain_unregister(&vtg->notifier_list, nb); 300 } 301 EXPORT_SYMBOL(sti_vtg_unregister_client); 302 303 static irqreturn_t vtg_irq_thread(int irq, void *arg) 304 { 305 struct sti_vtg *vtg = arg; 306 u32 event; 307 308 event = (vtg->irq_status & VTG_IRQ_TOP) ? 309 VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT; 310 311 raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id); 312 313 return IRQ_HANDLED; 314 } 315 316 static irqreturn_t vtg_irq(int irq, void *arg) 317 { 318 struct sti_vtg *vtg = arg; 319 320 vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS); 321 322 writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR); 323 324 /* force sync bus write */ 325 readl(vtg->regs + VTG_HOST_ITS); 326 327 return IRQ_WAKE_THREAD; 328 } 329 330 static int vtg_probe(struct platform_device *pdev) 331 { 332 struct device *dev = &pdev->dev; 333 struct device_node *np; 334 struct sti_vtg *vtg; 335 struct resource *res; 336 int ret; 337 338 vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL); 339 if (!vtg) 340 return -ENOMEM; 341 342 vtg->dev = dev; 343 vtg->np = pdev->dev.of_node; 344 345 /* Get Memory ressources */ 346 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 347 if (!res) { 348 DRM_ERROR("Get memory resource failed\n"); 349 return -ENOMEM; 350 } 351 vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 352 353 np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); 354 if (np) { 355 vtg->slave = of_vtg_find(np); 356 357 if (!vtg->slave) 358 return -EPROBE_DEFER; 359 } else { 360 vtg->irq = platform_get_irq(pdev, 0); 361 if (IS_ERR_VALUE(vtg->irq)) { 362 DRM_ERROR("Failed to get VTG interrupt\n"); 363 return vtg->irq; 364 } 365 366 RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list); 367 368 ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq, 369 vtg_irq_thread, IRQF_ONESHOT, 370 dev_name(dev), vtg); 371 if (IS_ERR_VALUE(ret)) { 372 DRM_ERROR("Failed to register VTG interrupt\n"); 373 return ret; 374 } 375 } 376 377 vtg_register(vtg); 378 platform_set_drvdata(pdev, vtg); 379 380 DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev)); 381 382 return 0; 383 } 384 385 static int vtg_remove(struct platform_device *pdev) 386 { 387 return 0; 388 } 389 390 static const struct of_device_id vtg_of_match[] = { 391 { .compatible = "st,vtg", }, 392 { /* sentinel */ } 393 }; 394 MODULE_DEVICE_TABLE(of, vtg_of_match); 395 396 struct platform_driver sti_vtg_driver = { 397 .driver = { 398 .name = "sti-vtg", 399 .owner = THIS_MODULE, 400 .of_match_table = vtg_of_match, 401 }, 402 .probe = vtg_probe, 403 .remove = vtg_remove, 404 }; 405 406 module_platform_driver(sti_vtg_driver); 407 408 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 409 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 410 MODULE_LICENSE("GPL"); 411