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_IRQ_BOTTOM BIT(0) 55 #define VTG_IRQ_TOP BIT(1) 56 #define VTG_IRQ_MASK (VTG_IRQ_TOP | VTG_IRQ_BOTTOM) 57 58 /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ 59 #define AWG_DELAY_HD (-9) 60 #define AWG_DELAY_ED (-8) 61 #define AWG_DELAY_SD (-7) 62 63 LIST_HEAD(vtg_lookup); 64 65 /** 66 * STI VTG structure 67 * 68 * @dev: pointer to device driver 69 * @data: data associated to the device 70 * @irq: VTG irq 71 * @type: VTG type (main or aux) 72 * @notifier_list: notifier callback 73 * @crtc_id: the crtc id for vblank event 74 * @slave: slave vtg 75 * @link: List node to link the structure in lookup list 76 */ 77 struct sti_vtg { 78 struct device *dev; 79 struct device_node *np; 80 void __iomem *regs; 81 int irq; 82 u32 irq_status; 83 struct raw_notifier_head notifier_list; 84 int crtc_id; 85 struct sti_vtg *slave; 86 struct list_head link; 87 }; 88 89 static void vtg_register(struct sti_vtg *vtg) 90 { 91 list_add_tail(&vtg->link, &vtg_lookup); 92 } 93 94 struct sti_vtg *of_vtg_find(struct device_node *np) 95 { 96 struct sti_vtg *vtg; 97 98 list_for_each_entry(vtg, &vtg_lookup, link) { 99 if (vtg->np == np) 100 return vtg; 101 } 102 return NULL; 103 } 104 EXPORT_SYMBOL(of_vtg_find); 105 106 static void vtg_reset(struct sti_vtg *vtg) 107 { 108 /* reset slave and then master */ 109 if (vtg->slave) 110 vtg_reset(vtg->slave); 111 112 writel(1, vtg->regs + VTG_DRST_AUTOC); 113 } 114 115 static void vtg_set_mode(struct sti_vtg *vtg, 116 int type, const struct drm_display_mode *mode) 117 { 118 u32 tmp; 119 120 if (vtg->slave) 121 vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); 122 123 writel(mode->htotal, vtg->regs + VTG_CLKLN); 124 writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN); 125 126 tmp = (mode->vtotal - mode->vsync_start + 1) << 16; 127 tmp |= mode->htotal - mode->hsync_start; 128 writel(tmp, vtg->regs + VTG_VID_TFO); 129 writel(tmp, vtg->regs + VTG_VID_BFO); 130 131 tmp = (mode->vdisplay + mode->vtotal - mode->vsync_start + 1) << 16; 132 tmp |= mode->hdisplay + mode->htotal - mode->hsync_start; 133 writel(tmp, vtg->regs + VTG_VID_TFS); 134 writel(tmp, vtg->regs + VTG_VID_BFS); 135 136 /* prepare VTG set 1 and 2 for HDMI and VTG set 3 for HD DAC */ 137 tmp = (mode->hsync_end - mode->hsync_start) << 16; 138 writel(tmp, vtg->regs + VTG_H_HD_1); 139 writel(tmp, vtg->regs + VTG_H_HD_2); 140 141 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 142 tmp |= 1; 143 writel(tmp, vtg->regs + VTG_TOP_V_VD_1); 144 writel(tmp, vtg->regs + VTG_BOT_V_VD_1); 145 writel(0, vtg->regs + VTG_TOP_V_HD_1); 146 writel(0, vtg->regs + VTG_BOT_V_HD_1); 147 148 /* prepare VTG set 2 for for HD DCS */ 149 writel(tmp, vtg->regs + VTG_TOP_V_VD_2); 150 writel(tmp, vtg->regs + VTG_BOT_V_VD_2); 151 writel(0, vtg->regs + VTG_TOP_V_HD_2); 152 writel(0, vtg->regs + VTG_BOT_V_HD_2); 153 154 /* prepare VTG set 3 for HD Analog in HD mode */ 155 tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16; 156 tmp |= mode->htotal + AWG_DELAY_HD; 157 writel(tmp, vtg->regs + VTG_H_HD_3); 158 159 tmp = (mode->vsync_end - mode->vsync_start) << 16; 160 tmp |= mode->vtotal; 161 writel(tmp, vtg->regs + VTG_TOP_V_VD_3); 162 writel(tmp, vtg->regs + VTG_BOT_V_VD_3); 163 164 tmp = (mode->htotal + AWG_DELAY_HD) << 16; 165 tmp |= mode->htotal + AWG_DELAY_HD; 166 writel(tmp, vtg->regs + VTG_TOP_V_HD_3); 167 writel(tmp, vtg->regs + VTG_BOT_V_HD_3); 168 169 /* mode */ 170 writel(type, vtg->regs + VTG_MODE); 171 } 172 173 static void vtg_enable_irq(struct sti_vtg *vtg) 174 { 175 /* clear interrupt status and mask */ 176 writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR); 177 writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR); 178 writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET); 179 } 180 181 void sti_vtg_set_config(struct sti_vtg *vtg, 182 const struct drm_display_mode *mode) 183 { 184 /* write configuration */ 185 vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); 186 187 vtg_reset(vtg); 188 189 /* enable irq for the vtg vblank synchro */ 190 if (vtg->slave) 191 vtg_enable_irq(vtg->slave); 192 else 193 vtg_enable_irq(vtg); 194 } 195 EXPORT_SYMBOL(sti_vtg_set_config); 196 197 /** 198 * sti_vtg_get_line_number 199 * 200 * @mode: display mode to be used 201 * @y: line 202 * 203 * Return the line number according to the display mode taking 204 * into account the Sync and Back Porch information. 205 * Video frame line numbers start at 1, y starts at 0. 206 * In interlaced modes the start line is the field line number of the odd 207 * field, but y is still defined as a progressive frame. 208 */ 209 u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) 210 { 211 u32 start_line = mode.vtotal - mode.vsync_start + 1; 212 213 if (mode.flags & DRM_MODE_FLAG_INTERLACE) 214 start_line *= 2; 215 216 return start_line + y; 217 } 218 EXPORT_SYMBOL(sti_vtg_get_line_number); 219 220 /** 221 * sti_vtg_get_pixel_number 222 * 223 * @mode: display mode to be used 224 * @x: row 225 * 226 * Return the pixel number according to the display mode taking 227 * into account the Sync and Back Porch information. 228 * Pixels are counted from 0. 229 */ 230 u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) 231 { 232 return mode.htotal - mode.hsync_start + x; 233 } 234 EXPORT_SYMBOL(sti_vtg_get_pixel_number); 235 236 int sti_vtg_register_client(struct sti_vtg *vtg, 237 struct notifier_block *nb, int crtc_id) 238 { 239 if (vtg->slave) 240 return sti_vtg_register_client(vtg->slave, nb, crtc_id); 241 242 vtg->crtc_id = crtc_id; 243 return raw_notifier_chain_register(&vtg->notifier_list, nb); 244 } 245 EXPORT_SYMBOL(sti_vtg_register_client); 246 247 int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) 248 { 249 if (vtg->slave) 250 return sti_vtg_unregister_client(vtg->slave, nb); 251 252 return raw_notifier_chain_unregister(&vtg->notifier_list, nb); 253 } 254 EXPORT_SYMBOL(sti_vtg_unregister_client); 255 256 static irqreturn_t vtg_irq_thread(int irq, void *arg) 257 { 258 struct sti_vtg *vtg = arg; 259 u32 event; 260 261 event = (vtg->irq_status & VTG_IRQ_TOP) ? 262 VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT; 263 264 raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id); 265 266 return IRQ_HANDLED; 267 } 268 269 static irqreturn_t vtg_irq(int irq, void *arg) 270 { 271 struct sti_vtg *vtg = arg; 272 273 vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS); 274 275 writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR); 276 277 /* force sync bus write */ 278 readl(vtg->regs + VTG_HOST_ITS); 279 280 return IRQ_WAKE_THREAD; 281 } 282 283 static int vtg_probe(struct platform_device *pdev) 284 { 285 struct device *dev = &pdev->dev; 286 struct device_node *np; 287 struct sti_vtg *vtg; 288 struct resource *res; 289 char irq_name[32]; 290 int ret; 291 292 vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL); 293 if (!vtg) 294 return -ENOMEM; 295 296 vtg->dev = dev; 297 vtg->np = pdev->dev.of_node; 298 299 /* Get Memory ressources */ 300 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 301 if (!res) { 302 DRM_ERROR("Get memory resource failed\n"); 303 return -ENOMEM; 304 } 305 vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 306 307 np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); 308 if (np) { 309 vtg->slave = of_vtg_find(np); 310 311 if (!vtg->slave) 312 return -EPROBE_DEFER; 313 } else { 314 vtg->irq = platform_get_irq(pdev, 0); 315 if (IS_ERR_VALUE(vtg->irq)) { 316 DRM_ERROR("Failed to get VTG interrupt\n"); 317 return vtg->irq; 318 } 319 320 snprintf(irq_name, sizeof(irq_name), "vsync-%s", 321 dev_name(vtg->dev)); 322 323 RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list); 324 325 ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq, 326 vtg_irq_thread, IRQF_ONESHOT, irq_name, vtg); 327 if (IS_ERR_VALUE(ret)) { 328 DRM_ERROR("Failed to register VTG interrupt\n"); 329 return ret; 330 } 331 } 332 333 vtg_register(vtg); 334 platform_set_drvdata(pdev, vtg); 335 336 DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev)); 337 338 return 0; 339 } 340 341 static int vtg_remove(struct platform_device *pdev) 342 { 343 return 0; 344 } 345 346 static const struct of_device_id vtg_of_match[] = { 347 { .compatible = "st,vtg", }, 348 { /* sentinel */ } 349 }; 350 MODULE_DEVICE_TABLE(of, vtg_of_match); 351 352 struct platform_driver sti_vtg_driver = { 353 .driver = { 354 .name = "sti-vtg", 355 .owner = THIS_MODULE, 356 .of_match_table = vtg_of_match, 357 }, 358 .probe = vtg_probe, 359 .remove = vtg_remove, 360 }; 361 362 module_platform_driver(sti_vtg_driver); 363 364 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 365 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 366 MODULE_LICENSE("GPL"); 367