11c06552aSJason Jin /* 21c06552aSJason Jin * T1042 platform DIU operation 31c06552aSJason Jin * 41c06552aSJason Jin * Copyright 2014 Freescale Semiconductor Inc. 51c06552aSJason Jin * 61c06552aSJason Jin * This program is free software; you can redistribute it and/or modify it 71c06552aSJason Jin * under the terms of the GNU General Public License as published by the 81c06552aSJason Jin * Free Software Foundation; either version 2 of the License, or (at your 91c06552aSJason Jin * option) any later version. 101c06552aSJason Jin */ 111c06552aSJason Jin 12f5daf77aSRandy Dunlap #include <linux/init.h> 131c06552aSJason Jin #include <linux/io.h> 141c06552aSJason Jin #include <linux/kernel.h> 15f5daf77aSRandy Dunlap #include <linux/module.h> 161c06552aSJason Jin #include <linux/of.h> 171c06552aSJason Jin #include <linux/of_address.h> 181c06552aSJason Jin 191c06552aSJason Jin #include <sysdev/fsl_soc.h> 201c06552aSJason Jin 211c06552aSJason Jin /*DIU Pixel ClockCR offset in scfg*/ 221c06552aSJason Jin #define CCSR_SCFG_PIXCLKCR 0x28 231c06552aSJason Jin 241c06552aSJason Jin /* DIU Pixel Clock bits of the PIXCLKCR */ 251c06552aSJason Jin #define PIXCLKCR_PXCKEN 0x80000000 261c06552aSJason Jin #define PIXCLKCR_PXCKINV 0x40000000 271c06552aSJason Jin #define PIXCLKCR_PXCKDLY 0x0000FF00 281c06552aSJason Jin #define PIXCLKCR_PXCLK_MASK 0x00FF0000 291c06552aSJason Jin 301c06552aSJason Jin /* Some CPLD register definitions */ 311c06552aSJason Jin #define CPLD_DIUCSR 0x16 321c06552aSJason Jin #define CPLD_DIUCSR_DVIEN 0x80 331c06552aSJason Jin #define CPLD_DIUCSR_BACKLIGHT 0x0f 341c06552aSJason Jin 351c06552aSJason Jin struct device_node *cpld_node; 361c06552aSJason Jin 371c06552aSJason Jin /** 381c06552aSJason Jin * t1042rdb_set_monitor_port: switch the output to a different monitor port 391c06552aSJason Jin */ 401c06552aSJason Jin static void t1042rdb_set_monitor_port(enum fsl_diu_monitor_port port) 411c06552aSJason Jin { 42af8511cfSYue Haibing void __iomem *cpld_base; 431c06552aSJason Jin 441c06552aSJason Jin cpld_base = of_iomap(cpld_node, 0); 451c06552aSJason Jin if (!cpld_base) { 461c06552aSJason Jin pr_err("%s: Could not map cpld registers\n", __func__); 471c06552aSJason Jin goto exit; 481c06552aSJason Jin } 491c06552aSJason Jin 501c06552aSJason Jin switch (port) { 511c06552aSJason Jin case FSL_DIU_PORT_DVI: 521c06552aSJason Jin /* Enable the DVI(HDMI) port, disable the DFP and 531c06552aSJason Jin * the backlight 541c06552aSJason Jin */ 551c06552aSJason Jin clrbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_DVIEN); 561c06552aSJason Jin break; 571c06552aSJason Jin case FSL_DIU_PORT_LVDS: 581c06552aSJason Jin /* 591c06552aSJason Jin * LVDS also needs backlight enabled, otherwise the display 601c06552aSJason Jin * will be blank. 611c06552aSJason Jin */ 621c06552aSJason Jin /* Enable the DFP port, disable the DVI*/ 631c06552aSJason Jin setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 8); 641c06552aSJason Jin setbits8(cpld_base + CPLD_DIUCSR, 0x01 << 4); 651c06552aSJason Jin setbits8(cpld_base + CPLD_DIUCSR, CPLD_DIUCSR_BACKLIGHT); 661c06552aSJason Jin break; 671c06552aSJason Jin default: 681c06552aSJason Jin pr_err("%s: Unsupported monitor port %i\n", __func__, port); 691c06552aSJason Jin } 701c06552aSJason Jin 711c06552aSJason Jin iounmap(cpld_base); 721c06552aSJason Jin exit: 731c06552aSJason Jin of_node_put(cpld_node); 741c06552aSJason Jin } 751c06552aSJason Jin 761c06552aSJason Jin /** 771c06552aSJason Jin * t1042rdb_set_pixel_clock: program the DIU's clock 781c06552aSJason Jin * @pixclock: pixel clock in ps (pico seconds) 791c06552aSJason Jin */ 801c06552aSJason Jin static void t1042rdb_set_pixel_clock(unsigned int pixclock) 811c06552aSJason Jin { 821c06552aSJason Jin struct device_node *scfg_np; 831c06552aSJason Jin void __iomem *scfg; 841c06552aSJason Jin unsigned long freq; 851c06552aSJason Jin u64 temp; 861c06552aSJason Jin u32 pxclk; 871c06552aSJason Jin 881c06552aSJason Jin scfg_np = of_find_compatible_node(NULL, NULL, "fsl,t1040-scfg"); 891c06552aSJason Jin if (!scfg_np) { 901c06552aSJason Jin pr_err("%s: Missing scfg node. Can not display video.\n", 911c06552aSJason Jin __func__); 921c06552aSJason Jin return; 931c06552aSJason Jin } 941c06552aSJason Jin 951c06552aSJason Jin scfg = of_iomap(scfg_np, 0); 961c06552aSJason Jin of_node_put(scfg_np); 971c06552aSJason Jin if (!scfg) { 981c06552aSJason Jin pr_err("%s: Could not map device. Can not display video.\n", 991c06552aSJason Jin __func__); 1001c06552aSJason Jin return; 1011c06552aSJason Jin } 1021c06552aSJason Jin 1031c06552aSJason Jin /* Convert pixclock into frequency */ 1041c06552aSJason Jin temp = 1000000000000ULL; 1051c06552aSJason Jin do_div(temp, pixclock); 1061c06552aSJason Jin freq = temp; 1071c06552aSJason Jin 1081c06552aSJason Jin /* 1091c06552aSJason Jin * 'pxclk' is the ratio of the platform clock to the pixel clock. 1101c06552aSJason Jin * This number is programmed into the PIXCLKCR register, and the valid 1111c06552aSJason Jin * range of values is 2-255. 1121c06552aSJason Jin */ 1131c06552aSJason Jin pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq); 1141c06552aSJason Jin pxclk = clamp_t(u32, pxclk, 2, 255); 1151c06552aSJason Jin 1161c06552aSJason Jin /* Disable the pixel clock, and set it to non-inverted and no delay */ 1171c06552aSJason Jin clrbits32(scfg + CCSR_SCFG_PIXCLKCR, 1181c06552aSJason Jin PIXCLKCR_PXCKEN | PIXCLKCR_PXCKDLY | PIXCLKCR_PXCLK_MASK); 1191c06552aSJason Jin 1201c06552aSJason Jin /* Enable the clock and set the pxclk */ 1211c06552aSJason Jin setbits32(scfg + CCSR_SCFG_PIXCLKCR, PIXCLKCR_PXCKEN | (pxclk << 16)); 1221c06552aSJason Jin 1231c06552aSJason Jin iounmap(scfg); 1241c06552aSJason Jin } 1251c06552aSJason Jin 1261c06552aSJason Jin /** 1271c06552aSJason Jin * t1042rdb_valid_monitor_port: set the monitor port for sysfs 1281c06552aSJason Jin */ 1291c06552aSJason Jin static enum fsl_diu_monitor_port 1301c06552aSJason Jin t1042rdb_valid_monitor_port(enum fsl_diu_monitor_port port) 1311c06552aSJason Jin { 1321c06552aSJason Jin switch (port) { 1331c06552aSJason Jin case FSL_DIU_PORT_DVI: 1341c06552aSJason Jin case FSL_DIU_PORT_LVDS: 1351c06552aSJason Jin return port; 1361c06552aSJason Jin default: 1371c06552aSJason Jin return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */ 1381c06552aSJason Jin } 1391c06552aSJason Jin } 1401c06552aSJason Jin 1411c06552aSJason Jin static int __init t1042rdb_diu_init(void) 1421c06552aSJason Jin { 1431c06552aSJason Jin cpld_node = of_find_compatible_node(NULL, NULL, "fsl,t1042rdb-cpld"); 1441c06552aSJason Jin if (!cpld_node) 1451c06552aSJason Jin return 0; 1461c06552aSJason Jin 1471c06552aSJason Jin diu_ops.set_monitor_port = t1042rdb_set_monitor_port; 1481c06552aSJason Jin diu_ops.set_pixel_clock = t1042rdb_set_pixel_clock; 1491c06552aSJason Jin diu_ops.valid_monitor_port = t1042rdb_valid_monitor_port; 1501c06552aSJason Jin 1511c06552aSJason Jin return 0; 1521c06552aSJason Jin } 1531c06552aSJason Jin 1541c06552aSJason Jin early_initcall(t1042rdb_diu_init); 155f5daf77aSRandy Dunlap 156f5daf77aSRandy Dunlap MODULE_LICENSE("GPL"); 157