Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | // SPDX-License-Identifier: GPL-2.0-or-later /* * T1042 platform DIU operation * * Copyright 2014 Freescale Semiconductor Inc. */ #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_address.h> #include <sysdev/fsl_soc.h> /*DIU Pixel ClockCR offset in scfg*/ #define CCSR_SCFG_PIXCLKCR 0x28 /* DIU Pixel Clock bits of the PIXCLKCR */ #define PIXCLKCR_PXCKEN 0x80000000 #define PIXCLKCR_PXCKINV 0x40000000 #define PIXCLKCR_PXCKDLY 0x0000FF00 #define PIXCLKCR_PXCLK_MASK 0x00FF0000 /* Some CPLD register definitions */ #define CPLD_DIUCSR 0x16 #define CPLD_DIUCSR_DVIEN 0x80 #define CPLD_DIUCSR_BACKLIGHT 0x0f struct device_node *cpld_node; /** * t1042rdb_set_monitor_port: switch the output to a different monitor port */ static void t1042rdb_set_monitor_port(enum fsl_diu_monitor_port port) { void __iomem *cpld_base; cpld_base = of_iomap(cpld_node, 0); if (!cpld_base) { pr_err("%s: Could not map cpld registers\n", __func__); goto exit; } switch (port) { case FSL_DIU_PORT_DVI: /* Enable the DVI(HDMI) port, disable the DFP and * the backlight */ clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN); break; case FSL_DIU_PORT_LVDS: /* * LVDS also needs backlight enabled, otherwise the display * will be blank. */ /* Enable the DFP port, disable the DVI*/ setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8); setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4); setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT); break; default: pr_err("%s: Unsupported monitor port %i\n", __func__, port); } iounmap(cpld_base); exit: of_node_put(cpld_node); } /** * t1042rdb_set_pixel_clock: program the DIU's clock * @pixclock: pixel clock in ps (pico seconds) */ static void t1042rdb_set_pixel_clock(unsigned int pixclock) { struct device_node *scfg_np; void __iomem *scfg; unsigned long freq; u64 temp; u32 pxclk; scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg"); if (!scfg_np) { pr_err("%s: Missing scfg node. Can not display video.\n", __func__); return; } scfg = of_iomap(scfg_np, 0); of_node_put(scfg_np); if (!scfg) { pr_err("%s: Could not map device. Can not display video.\n", __func__); return; } /* Convert pixclock into frequency */ temp = 1000000000000ULL; do_div(temp, pixclock); freq = temp; /* * 'pxclk' is the ratio of the platform clock to the pixel clock. * This number is programmed into the PIXCLKCR register, and the valid * range of values is 2-255. */ pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); pxclk = clamp_t(u32, pxclk, 2, 255); /* Disable the pixel clock, and set it to non-inverted and no delay */ clrbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK); /* Enable the clock and set the pxclk */ setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16)); iounmap(scfg); } /** * t1042rdb_valid_monitor_port: set the monitor port for sysfs */ static enum fsl_diu_monitor_port t1042rdb_valid_monitor_port(enum fsl_diu_monitor_port port) { switch (port) { case FSL_DIU_PORT_DVI: case FSL_DIU_PORT_LVDS: return port; default: return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ } } static int __init t1042rdb_diu_init(void) { cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t1042rdb-cpld"); if (!cpld_node) return 0; diu_ops.set_monitor_port = t1042rdb_set_monitor_port; diu_ops.set_pixel_clock = t1042rdb_set_pixel_clock; diu_ops.valid_monitor_port = t1042rdb_valid_monitor_port; return 0; } early_initcall(t1042rdb_diu_init); MODULE_LICENSE("GPL"); |