This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM335x LCD 16-bit configuration in Processor SDK

Other Parts Discussed in Thread: DA8XX

Hi Team,

We interfaced 16bit(565) lcd panel with our custom board which is based on am335xevmsk design.

The lcd panel was configured using the following guide.

http://processors.wiki.ti.com/index.php/?title=Sitara_SDK_Linux_LCDC_Porting_Guide&oldid=199382

We are using drivers/video/fbdev/da8xx-fb.c display fb driver and drivers/input/touchscreen/ti_am335x_tsc.c touchcreen driver.

The output of fbset command is

mode "320x240-76"
    # D: 8.000 MHz, H: 19.704 kHz, V: 76.079 Hz
    geometry 320 240 320 240 32
    timings 125000 68 17 10 7 1 2
    rgba 8/16,8/8,8/0,8/24
endmode

In the above command rgba shows 8,8,8,8 which is wrong.

It has to be 5,6,5.

da8xx-fb.c & am335x-evmsk.dts files are attached for your reference.

we have doubt in dts file configuration.

Kindly suggest us to interface the panel.

Thanks & Regards,

Geetha

/*
 * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/*
 * AM335x Starter Kit
 * http://www.ti.com/tool/tmdssk3358
 */

/dts-v1/;

#include "am33xx.dtsi"
#include <dt-bindings/pwm/pwm.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
/ {
	model = "TI AM335x EVM-SK";
	compatible = "ti,am335x-evmsk", "ti,am33xx";

	cpus {
		cpu@0 {
			cpu0-supply = <&vdd1_reg>;
		};
	};

	memory {
		device_type = "memory";
		reg = <0x80000000 0x10000000>; /* 256 MB */
	};

	vbat: fixedregulator@0 {
		compatible = "regulator-fixed";
		regulator-name = "vbat";
		regulator-min-microvolt = <5000000>;
		regulator-max-microvolt = <5000000>;
		regulator-boot-on;
	};

	lis3_reg: fixedregulator@1 {
		compatible = "regulator-fixed";
		regulator-name = "lis3_reg";
		regulator-boot-on;
	};

	wl12xx_vmmc: fixedregulator@2 {
		pinctrl-names = "default";
		pinctrl-0 = <&wl12xx_gpio>;
		compatible = "regulator-fixed";
		regulator-name = "vwl1271";
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
		gpio = <&gpio1 29 0>;
		startup-delay-us = <70000>;
		enable-active-high;
	};

	vtt_fixed: fixedregulator@3 {
		compatible = "regulator-fixed";
		regulator-name = "vtt";
		regulator-min-microvolt = <1500000>;
		regulator-max-microvolt = <1500000>;
		gpio = <&gpio0 7 GPIO_ACTIVE_HIGH>;
		regulator-always-on;
		regulator-boot-on;
		enable-active-high;
	};

	leds {
		pinctrl-names = "default";
		pinctrl-0 = <&user_leds_s0>;

		compatible = "gpio-leds";

		led@1 {
			label = "evmsk:green:usr0";
			gpios = <&gpio1 4 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		led@2 {
			label = "evmsk:green:usr1";
			gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>;
			default-state = "off";
		};

		led@3 {
			label = "evmsk:green:mmc0";
			gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "mmc0";
			default-state = "off";
		};

		led@4 {
			label = "evmsk:green:heartbeat";
			gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>;
			linux,default-trigger = "heartbeat";
			default-state = "off";
		};
	};

	gpio_buttons: gpio_buttons@0 {
		compatible = "gpio-keys";
		#address-cells = <1>;
		#size-cells = <0>;

		switch@1 {
			label = "button0";
			linux,code = <0x100>;
			gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
		};

		switch@2 {
			label = "button1";
			linux,code = <0x101>;
			gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
		};

		switch@3 {
			label = "button2";
			linux,code = <0x102>;
			gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
			gpio-key,wakeup;
		};

		switch@4 {
			label = "button3";
			linux,code = <0x103>;
			gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>;
		};
	};

	backlight {
		compatible = "pwm-backlight";
		//pwms = <&ecap2 0 50000 PWM_POLARITY_INVERTED>;
		pwms = <&ecap2 0 50000 0>;
		brightness-levels = <0 58 61 66 75 90 125 170 255>;
		default-brightness-level = <8>;
	};

	sound {
		compatible = "ti,da830-evm-audio";
		ti,model = "AM335x-EVMSK";
		//ti,audio-codec = <&tlv320aic3106>;
		ti,audio-codec = <&tlv320aic31xx>;
		ti,mcasp-controller = <&mcasp1>;
		ti,codec-clock-rate = <24000000>;
		ti,audio-routing =
			"Headphone Jack",       "HPLOUT",
			"Headphone Jack",       "HPROUT";
	};
	
	//panel {
	//	compatible = "ti,tilcdc,panel";
	//	pinctrl-names = "default";
	//	pinctrl-0 = <&lcd_pins_default>;
	//	pinctrl-1 = <&lcd_pins_sleep>;
	//	status = "okay";
	//	panel-info {
	//		ac-bias           = <255>;
	//		ac-bias-intrpt    = <0>;
	//		dma-burst-sz      = <16>;
	//		bpp               = <16>; //ana1
	//		fdd               = <0x80>;
	//		sync-edge         = <0>;
	//		sync-ctrl         = <1>;
	//		raster-order      = <0>;
	//		fifo-th           = <0>;
	//	};
	//    	display-timings {
	//		native-mode = <&timing0>;
	//		timing0:320x240 {
	//			hactive         = <320>;
	//			vactive         = <240>;
	//			hback-porch     = <68>;
	//			hfront-porch    = <17>;
	//			hsync-len       = <1>;
	//			vback-porch     = <10>;
	//			vfront-porch    = <7>;
	//			vsync-len       = <2>;
	//			clock-frequency = <6500000>;
	//			hsync-active    = <0>;
	//			vsync-active    = <0>;
	//		};
	//	};
	
	//};
	
};

&am33xx_pinmux {
	pinctrl-names = "default";
	pinctrl-0 = <&gpio_keys_s0 &clkout2_pin &ddr3_vtt_toggle>;

	ddr3_vtt_toggle: ddr3_vtt_toggle {
		pinctrl-single,pins = <
			0x164 (PIN_OUTPUT | MUX_MODE7)	/* ecap0_in_pwm0_out.gpio0_7 */
		>;
	};
	lcd_pins_default: lcd_pins_default {
                pinctrl-single,pins = <
                      /*  0x20 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad8.lcd_data23 */
                      /*  0x24 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad9.lcd_data22 */
                      /*  0x28 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad10.lcd_data21 */
                      /*  0x2c (PIN_OUTPUT | MUX_MODE1)      gpmc_ad11.lcd_data20 */
                      /*  0x30 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad12.lcd_data19 */
                      /*  0x34 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad13.lcd_data18 */
                      /*  0x38 (PIN_OUTPUT | MUX_MODE1)      gpmc_ad14.lcd_data17 */
                      /*  0x3c (PIN_OUTPUT | MUX_MODE1)      gpmc_ad15.lcd_data16 */
                        0xa0 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data0.lcd_data0 */
                        0xa4 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data1.lcd_data1 */
                        0xa8 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data2.lcd_data2 */
                        0xac (PIN_OUTPUT | MUX_MODE0)   /* lcd_data3.lcd_data3 */
                        0xb0 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data4.lcd_data4 */
                        0xb4 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data5.lcd_data5 */
                        0xb8 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data6.lcd_data6 */
                        0xbc (PIN_OUTPUT | MUX_MODE0)   /* lcd_data7.lcd_data7 */
                        0xc0 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data8.lcd_data8 */
                        0xc4 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data9.lcd_data9 */
                        0xc8 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data10.lcd_data10 */
                        0xcc (PIN_OUTPUT | MUX_MODE0)   /* lcd_data11.lcd_data11 */
                        0xd0 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data12.lcd_data12 */
                        0xd4 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data13.lcd_data13 */
			0xd8 (PIN_OUTPUT | MUX_MODE0)   /* lcd_data14.lcd_data14 */
                        0xdc (PIN_OUTPUT | MUX_MODE0)   /* lcd_data15.lcd_data15 */
                        0xe0 (PIN_OUTPUT | MUX_MODE0)   /* lcd_vsync.lcd_vsync */
                        0xe4 (PIN_OUTPUT | MUX_MODE0)   /* lcd_hsync.lcd_hsync */
                        0xe8 (PIN_OUTPUT | MUX_MODE0)   /* lcd_pclk.lcd_pclk */
                        0xec (PIN_OUTPUT | MUX_MODE0)   /* lcd_ac_bias_en.lcd_ac_bias_en */
                >;
        };

        lcd_pins_sleep: lcd_pins_sleep {
                pinctrl-single,pins = <
                      /*  0x20 (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad8.lcd_data23 */
                      /*  0x24 (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad9.lcd_data22 */
                      /*  0x28 (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad10.lcd_data21 */
                      /*  0x2c (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad11.lcd_data20 */
                      /*  0x30 (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad12.lcd_data19 */
                      /*  0x34 (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad13.lcd_data18 */
                      /* 0x38 (PIN_INPUT_PULLDOWN | MUX_MODE7)     gpmc_ad14.lcd_data17 */
                      /*  0x3c (PIN_INPUT_PULLDOWN | MUX_MODE7)    gpmc_ad15.lcd_data16 */
                        0xa0 (PULL_DISABLE | MUX_MODE7) /* lcd_data0.lcd_data0 */
			0xa4 (PULL_DISABLE | MUX_MODE7) /* lcd_data1.lcd_data1 */
                        0xa8 (PULL_DISABLE | MUX_MODE7) /* lcd_data2.lcd_data2 */
                        0xac (PULL_DISABLE | MUX_MODE7) /* lcd_data3.lcd_data3 */
                        0xb0 (PULL_DISABLE | MUX_MODE7) /* lcd_data4.lcd_data4 */
                        0xb4 (PULL_DISABLE | MUX_MODE7) /* lcd_data5.lcd_data5 */
                        0xb8 (PULL_DISABLE | MUX_MODE7) /* lcd_data6.lcd_data6 */
                        0xbc (PULL_DISABLE | MUX_MODE7) /* lcd_data7.lcd_data7 */
                        0xc0 (PULL_DISABLE | MUX_MODE7) /* lcd_data8.lcd_data8 */
                        0xc4 (PULL_DISABLE | MUX_MODE7) /* lcd_data9.lcd_data9 */
                        0xc8 (PULL_DISABLE | MUX_MODE7) /* lcd_data10.lcd_data10 */
                        0xcc (PULL_DISABLE | MUX_MODE7) /* lcd_data11.lcd_data11 */
                        0xd0 (PULL_DISABLE | MUX_MODE7) /* lcd_data12.lcd_data12 */
                        0xd4 (PULL_DISABLE | MUX_MODE7) /* lcd_data13.lcd_data13 */
                        0xd8 (PULL_DISABLE | MUX_MODE7) /* lcd_data14.lcd_data14 */
                        0xdc (PULL_DISABLE | MUX_MODE7) /* lcd_data15.lcd_data15 */
                        0xe0 (PIN_INPUT_PULLDOWN | MUX_MODE7)   /* lcd_vsync.lcd_vsync */
                        0xe4 (PIN_INPUT_PULLDOWN | MUX_MODE7)   /* lcd_hsync.lcd_hsync */
                        0xe8 (PIN_INPUT_PULLDOWN | MUX_MODE7)   /* lcd_pclk.lcd_pclk */
                        0xec (PIN_INPUT_PULLDOWN | MUX_MODE7)   /* lcd_ac_bias_en.lcd_ac_bias_en */
                >;
        };

	user_leds_s0: user_leds_s0 {
		pinctrl-single,pins = <
			0x10 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad4.gpio1_4 */
			0x14 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad5.gpio1_5 */
			0x18 (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad6.gpio1_6 */
			0x1c (PIN_OUTPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ad7.gpio1_7 */
		>;
	};

	gpio_keys_s0: gpio_keys_s0 {
		pinctrl-single,pins = <
			0x94 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_oen_ren.gpio2_3 */
			0x90 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_advn_ale.gpio2_2 */
			0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_wait0.gpio0_30 */
			0x9c (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* gpmc_ben0_cle.gpio2_5 */
		>;
	};

	i2c0_pins: pinmux_i2c0_pins {
		pinctrl-single,pins = <
			0x188 (PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_sda.i2c0_sda */
			0x18c (PIN_INPUT_PULLUP | MUX_MODE0)	/* i2c0_scl.i2c0_scl */
		>;
	};

	uart0_pins: pinmux_uart0_pins {
		pinctrl-single,pins = <
			0x170 (PIN_INPUT_PULLUP | MUX_MODE0)	/* uart0_rxd.uart0_rxd */
			0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0)		/* uart0_txd.uart0_txd */
		>;
	};

	clkout2_pin: pinmux_clkout2_pin {
		pinctrl-single,pins = <
			0x1b4 (PIN_OUTPUT_PULLDOWN | MUX_MODE3)		/* xdma_event_intr1.clkout2 */
		>;
	};

	ecap2_pins_default: backlight_pins {
		pinctrl-single,pins = <
			//0x19c 0x4	/* mcasp0_ahclkr.ecap2_in_pwm2_out MODE4 */
			0x19c (PIN_OUTPUT | MUX_MODE4)	/* mcasp0_ahclkr.ecap2_in_pwm2_out MODE4 */
		>;
	};

	ecap2_pins_sleep: ecap2_pins_sleep {
		pinctrl-single,pins = <
			0x19c (PIN_INPUT_PULLDOWN | MUX_MODE7)	/* mcasp0_ahclkr.ecap2_in_pwm2_out */
		>;
       	};

	cpsw_default: cpsw_default {
		pinctrl-single,pins = <
			/* Slave 1 */
			0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txen.rgmii1_tctl */
			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxdv.rgmii1_rctl */
			0x11c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd3.rgmii1_td3 */
			0x120 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd2.rgmii1_td2 */
			0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd1.rgmii1_td1 */
			0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txd0.rgmii1_td0 */
			0x12c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* mii1_txclk.rgmii1_tclk */
			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxclk.rgmii1_rclk */
			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd3.rgmii1_rd3 */
			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd2.rgmii1_rd2 */
			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd1.rgmii1_rd1 */
			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* mii1_rxd0.rgmii1_rd0 */

			/* Slave 2 */
			0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a0.rgmii2_tctl */
			0x44 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a1.rgmii2_rctl */
			0x48 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a2.rgmii2_td3 */
			0x4c (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a3.rgmii2_td2 */
			0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a4.rgmii2_td1 */
			0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a5.rgmii2_td0 */
			0x58 (PIN_OUTPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a6.rgmii2_tclk */
			0x5c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a7.rgmii2_rclk */
			0x60 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a8.rgmii2_rd3 */
			0x64 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a9.rgmii2_rd2 */
			0x68 (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a10.rgmii2_rd1 */
			0x6c (PIN_INPUT_PULLDOWN | MUX_MODE2)	/* gpmc_a11.rgmii2_rd0 */
		>;
	};

	cpsw_sleep: cpsw_sleep {
		pinctrl-single,pins = <
			/* Slave 1 reset value */
			0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x118 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x11c (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x120 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x12c (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x130 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x134 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x138 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7)

			/* Slave 2 reset value*/
			0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x44 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x48 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x4c (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x58 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x5c (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x60 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7)
		>;
	};

	davinci_mdio_default: davinci_mdio_default {
		pinctrl-single,pins = <
			/* MDIO */
			0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0)	/* mdio_data.mdio_data */
			0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0)			/* mdio_clk.mdio_clk */
		>;
	};

	davinci_mdio_sleep: davinci_mdio_sleep {
		pinctrl-single,pins = <
			/* MDIO reset value */
			0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
		>;
	};

	mmc1_pins_default: pinmux_mmc1_pins {
		pinctrl-single,pins = <
			0x0F0 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat3.mmc0_dat3 */
			0x0F4 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat2.mmc0_dat2 */
			0x0F8 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat1.mmc0_dat1 */
			0x0FC (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_dat0.mmc0_dat0 */
			0x100 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_clk.mmc0_clk */
			0x104 (PIN_INPUT_PULLUP | MUX_MODE0)	/* mmc0_cmd.mmc0_cmd */
			0x1A0 (PIN_INPUT_PULLUP | MUX_MODE7)	/* mcasp0_aclkr.gpio3_18 */
			0x160 (PIN_INPUT | MUX_MODE7)		/* spi0_cs1.gpio0_6 */
		>;
	};

	mmc1_pins_sleep: pinmux_mmc1_pins_sleep {
		pinctrl-single,pins = <
			0x0F0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x0F4 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x0F8 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x0FC (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x100 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x104 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x1A0 (PIN_INPUT_PULLDOWN | MUX_MODE7)
			0x160 (PIN_INPUT_PULLDOWN | MUX_MODE7)
		>;
	};

	mcasp1_pins: mcasp1_pins {
		pinctrl-single,pins = <
			0x10c (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_crs.mcasp1_aclkx */
			0x110 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* mii1_rxerr.mcasp1_fsx */
			0x108 (PIN_OUTPUT_PULLDOWN | MUX_MODE4) /* mii1_col.mcasp1_axr2 */
			0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
		>;
	};

	mmc2_pins: pinmux_mmc2_pins {
		pinctrl-single,pins = <
			0x74 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_31 */
			0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
			0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
			0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
			0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
			0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
			0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
		>;
	};

	wl12xx_gpio: pinmux_wl12xx_gpio {
		pinctrl-single,pins = <
			0x7c (PIN_OUTPUT_PULLUP | MUX_MODE7) /* gpmc_csn0.gpio1_29 */
		>;
	};
};

&uart0 {
	pinctrl-names = "default";
	pinctrl-0 = <&uart0_pins>;

	status = "okay";
};

&i2c0 {
	pinctrl-names = "default";
	pinctrl-0 = <&i2c0_pins>;

	status = "okay";
	clock-frequency = <400000>;

	tps: tps@2d {
		reg = <0x2d>;
	};
	/*ana1*/
	rx8025: rx8025@32 {   
		compatible = "epson,rx8025-rtc";
		reg = <0x32>;
	};

	eeprom: eeprom@50 {
		compatible = "atmel,24c64";
		reg = <0x50>;
	};

	adp5588-keys@34 {
		status = "okay";
		compatible = "adp5588-keys";
		reg = <0x34>;
		interrupt-parent = <&gpio0>;
                interrupts = <31 IRQ_TYPE_LEVEL_LOW>;
		adp5588-keys,rows = <5>;
		adp5588-keys,cols = <10>;
	
	};

/*	lis331dlh: lis331dlh@18 {
		compatible = "st,lis331dlh", "st,lis3lv02d";
		reg = <0x18>;
		Vdd-supply = <&lis3_reg>;
		Vdd_IO-supply = <&lis3_reg>;

		st,click-single-x;
		st,click-single-y;
		st,click-single-z;
		st,click-thresh-x = <10>;
		st,click-thresh-y = <10>;
		st,click-thresh-z = <10>;
		st,irq1-click;
		st,irq2-click;
		st,wakeup-x-lo;
		st,wakeup-x-hi;
		st,wakeup-y-lo;
		st,wakeup-y-hi;
		st,wakeup-z-lo;
		st,wakeup-z-hi;
		st,min-limit-x = <120>;
		st,min-limit-y = <120>;
		st,min-limit-z = <140>;
		st,max-limit-x = <550>;
		st,max-limit-y = <550>;
		st,max-limit-z = <750>;
	};*/

	 tlv320aic31xx: tlv320aic31xx@18 {
		compatible = "ti,tlv320aic31xx";
		reg = <0x18>;
		status = "okay";

		/* Regulators */
		AVDD-supply = <&vaux2_reg>;
		IOVDD-supply = <&vaux2_reg>;
		DRVDD-supply = <&vaux2_reg>;
		DVDD-supply = <&vbat>;
	};
};

&usb {
	status = "okay";
};

&usb_ctrl_mod {
	status = "okay";
};

&usb0_phy {
	status = "okay";
};

&usb1_phy {
	status = "okay";
};

&usb0 {
	status = "okay";
};

&usb1 {
	status = "okay";
	dr_mode = "host";
};

&cppi41dma  {
	status = "okay";
};
&ecap2 {
	staus = "okay";
};

&epwmss2 {
	status = "okay";

	ecap2: ecap@48304100 {
		status = "okay";
		pinctrl-names = "default", "sleep";
		//pinctrl-names = "default";
		pinctrl-0 = <&ecap2_pins_default>;
		pinctrl-1 = <&ecap2_pins_sleep>;
	};
};

&wkup_m3_ipc {
	ti,needs-vtt-toggle;
	ti,vtt-gpio-pin = <7>;
	ti,scale-data-fw = "am335x-evm-scale-data.bin";
};

#include "tps65910.dtsi"

&tps {
	vcc1-supply = <&vbat>;
	vcc2-supply = <&vbat>;
	vcc3-supply = <&vbat>;
	vcc4-supply = <&vbat>;
	vcc5-supply = <&vbat>;
	vcc6-supply = <&vbat>;
	vcc7-supply = <&vbat>;
	vccio-supply = <&vbat>;

	regulators {
		vrtc_reg: regulator@0 {
			regulator-always-on;
		};

		vio_reg: regulator@1 {
			regulator-always-on;
		};

		vdd1_reg: regulator@2 {
			/* VDD_MPU voltage limits 0.95V - 1.325V with +/-4% tolerance */
			regulator-name = "vdd_mpu";
			regulator-min-microvolt = <912500>;
			regulator-max-microvolt = <1378000>;
			regulator-boot-on;
			regulator-always-on;
		};

		vdd2_reg: regulator@3 {
			/* VDD_CORE voltage limits 0.95V - 1.1V with +/-4% tolerance */
			regulator-name = "vdd_core";
			regulator-min-microvolt = <912500>;
			regulator-max-microvolt = <1150000>;
			regulator-boot-on;
			regulator-always-on;
		};

		vdd3_reg: regulator@4 {
			regulator-always-on;
		};

		vdig1_reg: regulator@5 {
			regulator-always-on;
		};

		vdig2_reg: regulator@6 {
			regulator-always-on;
		};

		vpll_reg: regulator@7 {
			regulator-always-on;
		};

		vdac_reg: regulator@8 {
			regulator-always-on;
		};

		vaux1_reg: regulator@9 {
			regulator-always-on;
		};

		vaux2_reg: regulator@10 {
			regulator-always-on;
		};

		vaux33_reg: regulator@11 {
			regulator-always-on;
		};

		vmmc_reg: regulator@12 {
			regulator-min-microvolt = <1800000>;
			regulator-max-microvolt = <3300000>;
			regulator-always-on;
		};
	};
};

&mac {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&cpsw_default>;
	pinctrl-1 = <&cpsw_sleep>;
	dual_emac = <1>;
	status = "okay";
};

&davinci_mdio {
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&davinci_mdio_default>;
	pinctrl-1 = <&davinci_mdio_sleep>;
	status = "okay";
};

&cpsw_emac0 {
	phy_id = <&davinci_mdio>, <0>;
	phy-mode = "rgmii-txid";
	dual_emac_res_vlan = <1>;
};

&cpsw_emac1 {
	phy_id = <&davinci_mdio>, <1>;
	phy-mode = "rgmii-txid";
	dual_emac_res_vlan = <2>;
};

&mmc1 {
	status = "okay";
	vmmc-supply = <&vmmc_reg>;
	bus-width = <4>;
	pinctrl-names = "default", "sleep";
	pinctrl-0 = <&mmc1_pins_default>;
	pinctrl-1 = <&mmc1_pins_sleep>;
	cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
};

&sham {
	status = "okay";
};

&aes {
	status = "okay";
};

&gpio0 {
	ti,no-reset-on-init;
};

&mmc2 {
	status = "okay";
	vmmc-supply = <&wl12xx_vmmc>;
	ti,non-removable;
	bus-width = <4>;
	cap-power-off-card;
	keep-power-in-suspend;
	pinctrl-names = "default";
	pinctrl-0 = <&mmc2_pins>;

	#address-cells = <1>;
	#size-cells = <0>;
	wlcore: wlcore@2 {
		compatible = "ti,wl1271";
		reg = <2>;
		interrupt-parent = <&gpio0>;
		/*interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; /* gpio 31 */
		ref-clock-frequency = <38400000>;
	};
};

&mcasp1 {
		pinctrl-names = "default";
		pinctrl-0 = <&mcasp1_pins>;

		status = "okay";

		op-mode = <0>;          /* MCASP_IIS_MODE */
		tdm-slots = <2>;
		/* 4 serializers */
		serial-dir = <  /* 0: INACTIVE, 1: TX, 2: RX */
			0 0 1 2
		>;
		tx-num-evt = <32>;
		rx-num-evt = <32>;
};

&tscadc {
	status = "okay";
	tsc {
		ti,wires = <4>;
		ti,x-plate-resistance = <200>;
		ti,coordinate-readouts = <5>;
		ti,wire-config = <0x00 0x11 0x22 0x33>;
	};
	adc {

		ti,adc-channels = <4 5 6 7>;

	};
};

&lcdc {
        status = "okay";
	pinctrl-names = "default","sleep";
	pinctrl-0 = <&lcd_pins_default>;
	pinctrl-1 = <&lcd_pins_sleep>;
	display-timings {
		native-mode = <&timing0>;
		timing0:320x240p16 {
			hactive         = <320>;
			vactive         = <240>;
			hback-porch     = <68>;
			hfront-porch    = <17>;
			hsync-len       = <1>;
			vback-porch     = <10>;
			vfront-porch    = <7>;
			vsync-len       = <2>;
			clock-frequency = <6500000>;
			hsync-active    = <0>;
			vsync-active    = <0>;
		};
	};
	
};

&sgx {
	status = "okay";
};

/*
 * Copyright (C) 2008-2009 MontaVista Software Inc.
 * Copyright (C) 2008-2009 Texas Instruments Inc
 *
 * Based on the LCD driver for TI Avalanche processors written by
 * Ajay Singh and Shalom Hai.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option)any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/pm_runtime.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/clk.h>
#include <linux/cpufreq.h>
#include <linux/console.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/lcm.h>
#include <video/of_display_timing.h>
#include <video/da8xx-fb.h>
#include <asm/div64.h>

#define DRIVER_NAME "da8xx_lcdc"

#define LCD_VERSION_1	1
#define LCD_VERSION_2	2

/* LCD Status Register */
#define LCD_END_OF_FRAME1		BIT(9)
#define LCD_END_OF_FRAME0		BIT(8)
#define LCD_PL_LOAD_DONE		BIT(6)
#define LCD_FIFO_UNDERFLOW		BIT(5)
#define LCD_SYNC_LOST			BIT(2)
#define LCD_FRAME_DONE			BIT(0)

/* LCD DMA Control Register */
#define LCD_DMA_BURST_SIZE(x)		((x) << 4)
#define LCD_DMA_BURST_1			0x0
#define LCD_DMA_BURST_2			0x1
#define LCD_DMA_BURST_4			0x2
#define LCD_DMA_BURST_8			0x3
#define LCD_DMA_BURST_16		0x4
#define LCD_V1_END_OF_FRAME_INT_ENA	BIT(2)
#define LCD_V2_END_OF_FRAME0_INT_ENA	BIT(8)
#define LCD_V2_END_OF_FRAME1_INT_ENA	BIT(9)
#define LCD_DUAL_FRAME_BUFFER_ENABLE	BIT(0)

/* LCD Control Register */
#define LCD_CLK_DIVISOR(x)		((x) << 8)
#define LCD_RASTER_MODE			0x01

/* LCD Raster Control Register */
#define LCD_PALETTE_LOAD_MODE(x)	((x) << 20)
#define PALETTE_AND_DATA		0x00
#define PALETTE_ONLY			0x01
#define DATA_ONLY			0x02

#define LCD_MONO_8BIT_MODE		BIT(9)
#define LCD_RASTER_ORDER		BIT(8)
#define LCD_TFT_MODE			BIT(7)
#define LCD_V1_UNDERFLOW_INT_ENA	BIT(6)
#define LCD_V2_UNDERFLOW_INT_ENA	BIT(5)
#define LCD_V1_PL_INT_ENA		BIT(4)
#define LCD_V2_PL_INT_ENA		BIT(6)
#define LCD_MONOCHROME_MODE		BIT(1)
#define LCD_RASTER_ENABLE		BIT(0)
#define LCD_TFT_ALT_ENABLE		BIT(23)
#define LCD_STN_565_ENABLE		BIT(24)
#define LCD_V2_DMA_CLK_EN		BIT(2)
#define LCD_V2_LIDD_CLK_EN		BIT(1)
#define LCD_V2_CORE_CLK_EN		BIT(0)
#define LCD_V2_LPP_B10			26
#define LCD_V2_TFT_24BPP_MODE		BIT(25)
#define LCD_V2_TFT_24BPP_UNPACK		BIT(26)

/* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x)	((x) << 16)
#define LCD_AC_BIAS_FREQUENCY(x)		((x) << 8)
#define LCD_SYNC_CTRL				BIT(25)
#define LCD_SYNC_EDGE				BIT(24)
#define LCD_INVERT_PIXEL_CLOCK			BIT(22)
#define LCD_INVERT_LINE_CLOCK			BIT(21)
#define LCD_INVERT_FRAME_CLOCK			BIT(20)

/* LCD Block */
#define  LCD_PID_REG				0x0
#define  LCD_CTRL_REG				0x4
#define  LCD_STAT_REG				0x8
#define  LCD_RASTER_CTRL_REG			0x28
#define  LCD_RASTER_TIMING_0_REG		0x2C
#define  LCD_RASTER_TIMING_1_REG		0x30
#define  LCD_RASTER_TIMING_2_REG		0x34
#define  LCD_DMA_CTRL_REG			0x40
#define  LCD_DMA_FRM_BUF_BASE_ADDR_0_REG	0x44
#define  LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG	0x48
#define  LCD_DMA_FRM_BUF_BASE_ADDR_1_REG	0x4C
#define  LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG	0x50

/* Interrupt Registers available only in Version 2 */
#define  LCD_RAW_STAT_REG			0x58
#define  LCD_MASKED_STAT_REG			0x5c
#define  LCD_INT_ENABLE_SET_REG			0x60
#define  LCD_INT_ENABLE_CLR_REG			0x64
#define  LCD_END_OF_INT_IND_REG			0x68

/* Clock registers available only on Version 2 */
#define  LCD_CLK_ENABLE_REG			0x6c
#define  LCD_CLK_RESET_REG			0x70
#define  LCD_CLK_MAIN_RESET			BIT(3)

#define LCD_NUM_BUFFERS	2

#define PALETTE_SIZE	256

#define	CLK_MIN_DIV	2
#define	CLK_MAX_DIV	255

static void __iomem *da8xx_fb_reg_base;
static unsigned int lcd_revision;
static irq_handler_t lcdc_irq_handler;
static wait_queue_head_t frame_done_wq;
static int frame_done_flag;

static unsigned int lcdc_read(unsigned int addr)
{
	return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr));
}

static void lcdc_write(unsigned int val, unsigned int addr)
{
	__raw_writel(val, da8xx_fb_reg_base + (addr));
}

struct da8xx_fb_par {
	struct device		*dev;
	resource_size_t p_palette_base;
	unsigned char *v_palette_base;
	dma_addr_t		vram_phys;
	unsigned long		vram_size;
	void			*vram_virt;
	unsigned int		dma_start;
	unsigned int		dma_end;
	struct clk *lcdc_clk;
	int irq;
	unsigned int palette_sz;
	int blank;
	wait_queue_head_t	vsync_wait;
	int			vsync_flag;
	int			vsync_timeout;
	spinlock_t		lock_for_chan_update;

	/*
	 * LCDC has 2 ping pong DMA channels, channel 0
	 * and channel 1.
	 */
	unsigned int		which_dma_channel_done;
#ifdef CONFIG_CPU_FREQ
	struct notifier_block	freq_transition;
#endif
	unsigned int		lcdc_clk_rate;
	void (*panel_power_ctrl)(int);
	u32 pseudo_palette[16];
	struct fb_videomode	mode;
	struct lcd_ctrl_config	cfg;
};

static struct fb_var_screeninfo da8xx_fb_var;

static struct fb_fix_screeninfo da8xx_fb_fix = {
	.id = "DA8xx FB Drv",
	.type = FB_TYPE_PACKED_PIXELS,
	.type_aux = 0,
	.visual = FB_VISUAL_PSEUDOCOLOR,
	.xpanstep = 0,
	.ypanstep = 1,
	.ywrapstep = 0,
	.accel = FB_ACCEL_NONE
};

static vsync_callback_t vsync_cb_handler;
static void *vsync_cb_arg;

static struct fb_videomode known_lcd_panels[] = {
	/* Sharp LCD035Q3DG01 */
	[0] = {
		.name           = "Sharp_LCD035Q3DG01",
		.xres           = 320,
		.yres           = 240,
		.pixclock       = KHZ2PICOS(4607),
		.left_margin    = 6,
		.right_margin   = 8,
		.upper_margin   = 2,
		.lower_margin   = 2,
		.hsync_len      = 0,
		.vsync_len      = 0,
		.sync           = FB_SYNC_CLK_INVERT |
			FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
	},
	/* Sharp LK043T1DG01 */
	[1] = {
		.name           = "Sharp_LK043T1DG01",
		.xres           = 480,
		.yres           = 272,
		.pixclock       = KHZ2PICOS(7833),
		.left_margin    = 2,
		.right_margin   = 2,
		.upper_margin   = 2,
		.lower_margin   = 2,
		.hsync_len      = 41,
		.vsync_len      = 10,
		.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
		.flag           = 0,
	},
	[2] = {
		/* Hitachi SP10Q010 */
		.name           = "SP10Q010",
		.xres           = 320,
		.yres           = 240,
		.pixclock       = KHZ2PICOS(7833),
		.left_margin    = 10,
		.right_margin   = 10,
		.upper_margin   = 10,
		.lower_margin   = 10,
		.hsync_len      = 10,
		.vsync_len      = 10,
		.sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
		.flag           = 0,
	},
	[3] = {
		/* Densitron 84-0023-001T */
		.name           = "Densitron_84-0023-001T",
		.xres           = 320,
		.yres           = 240,
		.pixclock       = KHZ2PICOS(6400),
		.left_margin    = 0,
		.right_margin   = 0,
		.upper_margin   = 0,
		.lower_margin   = 0,
		.hsync_len      = 30,
		.vsync_len      = 3,
		.sync           = 0,
	},
};

static bool da8xx_fb_is_raster_enabled(void)
{
	return !!(lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE);
}

/* Enable the Raster Engine of the LCD Controller */
static void lcd_enable_raster(void)
{
	u32 reg;

	/* Put LCDC in reset for several cycles */
	if (lcd_revision == LCD_VERSION_2)
		/* Write 1 to reset LCDC */
		lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
	mdelay(1);

	/* Bring LCDC out of reset */
	if (lcd_revision == LCD_VERSION_2)
		lcdc_write(0, LCD_CLK_RESET_REG);
	mdelay(1);

	/* Above reset sequence doesnot reset register context */
	reg = lcdc_read(LCD_RASTER_CTRL_REG);
	if (!(reg & LCD_RASTER_ENABLE))
		lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
}

/* Disable the Raster Engine of the LCD Controller */
static void lcd_disable_raster(enum da8xx_frame_complete wait_for_frame_done)
{
	u32 reg;
	int ret;

	reg = lcdc_read(LCD_RASTER_CTRL_REG);
	if (reg & LCD_RASTER_ENABLE)
		lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
	else
		/* return if already disabled */
		return;

	if ((wait_for_frame_done == DA8XX_FRAME_WAIT) &&
			(lcd_revision == LCD_VERSION_2)) {
		frame_done_flag = 0;
		ret = wait_event_interruptible_timeout(frame_done_wq,
				frame_done_flag != 0,
				msecs_to_jiffies(50));
		if (ret == 0)
			pr_err("LCD Controller timed out\n");
	}
}

static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
{
	u32 start;
	u32 end;
	u32 reg_ras;
	u32 reg_dma;
	u32 reg_int;

	/* init reg to clear PLM (loading mode) fields */
	reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
	reg_ras &= ~(3 << 20);

	reg_dma  = lcdc_read(LCD_DMA_CTRL_REG);

	if (load_mode == LOAD_DATA) {
		start    = par->dma_start;
		end      = par->dma_end;

		reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
		if (lcd_revision == LCD_VERSION_1) {
			reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
		} else {
			reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
				LCD_V2_END_OF_FRAME0_INT_ENA |
				LCD_V2_END_OF_FRAME1_INT_ENA |
				LCD_FRAME_DONE | LCD_SYNC_LOST;
			lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
		}
		reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;

		lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
		lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
		lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
		lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
	} else if (load_mode == LOAD_PALETTE) {
		start    = par->p_palette_base;
		end      = start + par->palette_sz - 1;

		reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);

		if (lcd_revision == LCD_VERSION_1) {
		//if (lcd_revision == LCD_VERSION_2) {
			reg_ras |= LCD_V1_PL_INT_ENA;
		} else {
			reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
				LCD_V2_PL_INT_ENA;
			lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
		}

		lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
		lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
	}

	lcdc_write(reg_dma, LCD_DMA_CTRL_REG);
	lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);

	/*
	 * The Raster enable bit must be set after all other control fields are
	 * set.
	 */
	lcd_enable_raster();
}

/* Configure the Burst Size and fifo threhold of DMA */
static int lcd_cfg_dma(int burst_size, int fifo_th)
{
	u32 reg;

	reg = lcdc_read(LCD_DMA_CTRL_REG) & 0x00000001;
	switch (burst_size) {
	case 1:
		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
		break;
	case 2:
		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
		break;
	case 4:
		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
		break;
	case 8:
		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
		break;
	case 16:
	default:
		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
		break;
	}

	reg |= (fifo_th << 8);

	lcdc_write(reg, LCD_DMA_CTRL_REG);

	return 0;
}

static void lcd_cfg_ac_bias(int period, int transitions_per_int)
{
	u32 reg;

	/* Set the AC Bias Period and Number of Transisitons per Interrupt */
	reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & 0xFFF00000;
	reg |= LCD_AC_BIAS_FREQUENCY(period) |
		LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
	lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
}

static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
		int front_porch)
{
	u32 reg;

	reg = lcdc_read(LCD_RASTER_TIMING_0_REG) & 0x3ff;
	reg |= (((back_porch-1) & 0xff) << 24)
	    | (((front_porch-1) & 0xff) << 16)
	    | (((pulse_width-1) & 0x3f) << 10);
	lcdc_write(reg, LCD_RASTER_TIMING_0_REG);

	/*
	 * LCDC Version 2 adds some extra bits that increase the allowable
	 * size of the horizontal timing registers.
	 * remember that the registers use 0 to represent 1 so all values
	 * that get set into register need to be decremented by 1
	 */
	if (lcd_revision == LCD_VERSION_2) {
		/* Mask off the bits we want to change */
		reg = lcdc_read(LCD_RASTER_TIMING_2_REG) & ~0x780000ff;
		reg |= ((front_porch-1) & 0x300) >> 8;
		reg |= ((back_porch-1) & 0x300) >> 4;
		reg |= ((pulse_width-1) & 0x3c0) << 21;
		lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
	}
}

static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
		int front_porch)
{
	u32 reg;

	reg = lcdc_read(LCD_RASTER_TIMING_1_REG) & 0x3ff;
	reg |= ((back_porch & 0xff) << 24)
	    | ((front_porch & 0xff) << 16)
	    | (((pulse_width-1) & 0x3f) << 10);
	lcdc_write(reg, LCD_RASTER_TIMING_1_REG);
}

static int lcd_cfg_display(const struct lcd_ctrl_config *cfg,
		struct fb_videomode *panel)
{
	u32 reg;
	u32 reg_int;

	reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
						LCD_MONO_8BIT_MODE |
						LCD_MONOCHROME_MODE);

	switch (cfg->panel_shade) {
	case MONOCHROME:
		reg |= LCD_MONOCHROME_MODE;
		if (cfg->mono_8bit_mode)
			reg |= LCD_MONO_8BIT_MODE;
		break;
	case COLOR_ACTIVE:
		reg |= LCD_TFT_MODE;
		if (cfg->tft_alt_mode)
			reg |= LCD_TFT_ALT_ENABLE;
		break;

	case COLOR_PASSIVE:
		/* AC bias applicable only for Pasive panels */
		lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
		if (cfg->bpp == 12 && cfg->stn_565_mode)
			reg |= LCD_STN_565_ENABLE;
		break;

	default:
		return -EINVAL;
	}

	/* enable additional interrupts here */
	if (lcd_revision == LCD_VERSION_1) {
		reg |= LCD_V1_UNDERFLOW_INT_ENA;
	} else {
		reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
			LCD_V2_UNDERFLOW_INT_ENA;
		lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
	}

	lcdc_write(reg, LCD_RASTER_CTRL_REG);

	reg = lcdc_read(LCD_RASTER_TIMING_2_REG);

	reg |= LCD_SYNC_CTRL;

	if (cfg->sync_edge)
		reg |= LCD_SYNC_EDGE;
	else
		reg &= ~LCD_SYNC_EDGE;

	if ((panel->sync & FB_SYNC_HOR_HIGH_ACT) == 0)
		reg |= LCD_INVERT_LINE_CLOCK;
	else
		reg &= ~LCD_INVERT_LINE_CLOCK;

	if ((panel->sync & FB_SYNC_VERT_HIGH_ACT) == 0)
		reg |= LCD_INVERT_FRAME_CLOCK;
	else
		reg &= ~LCD_INVERT_FRAME_CLOCK;

	lcdc_write(reg, LCD_RASTER_TIMING_2_REG);

	return 0;
}

static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
		u32 bpp, u32 raster_order)
{
	u32 reg;

	if (bpp > 16 && lcd_revision == LCD_VERSION_1)
		return -EINVAL;

	/* Set the Panel Width */
	/* Pixels per line = (PPL + 1)*16 */
	if (lcd_revision == LCD_VERSION_1) {
		/*
		 * 0x3F in bits 4..9 gives max horizontal resolution = 1024
		 * pixels.
		 */
		width &= 0x3f0;
	} else {
		/*
		 * 0x7F in bits 4..10 gives max horizontal resolution = 2048
		 * pixels.
		 */
		width &= 0x7f0;
	}

	reg = lcdc_read(LCD_RASTER_TIMING_0_REG);
	reg &= 0xfffffc00;
	if (lcd_revision == LCD_VERSION_1) {
		reg |= ((width >> 4) - 1) << 4;
	} else {
		width = (width >> 4) - 1;
		reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
	}
	lcdc_write(reg, LCD_RASTER_TIMING_0_REG);

	/* Set the Panel Height */
	/* Set bits 9:0 of Lines Per Pixel */
	reg = lcdc_read(LCD_RASTER_TIMING_1_REG);
	reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
	lcdc_write(reg, LCD_RASTER_TIMING_1_REG);

	/* Set bit 10 of Lines Per Pixel */
	if (lcd_revision == LCD_VERSION_2) {
		reg = lcdc_read(LCD_RASTER_TIMING_2_REG);
		reg |= ((height - 1) & 0x400) << 16;
		lcdc_write(reg, LCD_RASTER_TIMING_2_REG);
	}

	/* Set the Raster Order of the Frame Buffer */
	reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8);
	if (raster_order)
		reg |= LCD_RASTER_ORDER;

	par->palette_sz = 16 * 2;

	switch (bpp) {
	case 1:
	case 2:
	case 4:
	case 16:
		break;
	case 24:
		reg |= LCD_V2_TFT_24BPP_MODE;
		break;
	case 32:
		reg |= LCD_V2_TFT_24BPP_MODE;
		reg |= LCD_V2_TFT_24BPP_UNPACK;
		break;
	case 8:
		par->palette_sz = 256 * 2;
		break;

	default:
		return -EINVAL;
	}

	lcdc_write(reg, LCD_RASTER_CTRL_REG);

	return 0;
}

#define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
			      unsigned blue, unsigned transp,
			      struct fb_info *info)
{
	struct da8xx_fb_par *par = info->par;
	unsigned short *palette = (unsigned short *) par->v_palette_base;
	u_short pal;
	int update_hw = 0;

	if (regno > 255)
		return 1;

	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
		return 1;

	if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
		return -EINVAL;

	switch (info->fix.visual) {
	case FB_VISUAL_TRUECOLOR:
		red = CNVT_TOHW(red, info->var.red.length);
		green = CNVT_TOHW(green, info->var.green.length);
		blue = CNVT_TOHW(blue, info->var.blue.length);
		break;
	case FB_VISUAL_PSEUDOCOLOR:
		switch (info->var.bits_per_pixel) {
		case 4:
			if (regno > 15)
				return -EINVAL;

			if (info->var.grayscale) {
				pal = regno;
			} else {
				red >>= 4;
				green >>= 8;
				blue >>= 12;

				pal = red & 0x0f00;
				pal |= green & 0x00f0;
				pal |= blue & 0x000f;
			}
			if (regno == 0)
				pal |= 0x2000;
			palette[regno] = pal;
			break;

		case 8:
			red >>= 4;
			green >>= 8;
			blue >>= 12;

			pal = (red & 0x0f00);
			pal |= (green & 0x00f0);
			pal |= (blue & 0x000f);

			if (palette[regno] != pal) {
				update_hw = 1;
				palette[regno] = pal;
			}
			break;
		}
		break;
	}

	/* Truecolor has hardware independent palette */
	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
		u32 v;

		if (regno > 15)
			return -EINVAL;

		v = (red << info->var.red.offset) |
			(green << info->var.green.offset) |
			(blue << info->var.blue.offset);

		((u32 *) (info->pseudo_palette))[regno] = v;
		if (palette[0] != 0x4000) {
			update_hw = 1;
			palette[0] = 0x4000;
		}
	}

	/* Update the palette in the h/w as needed. */
	if (update_hw)
		lcd_blit(LOAD_PALETTE, par);

	return 0;
}
#undef CNVT_TOHW

static void da8xx_fb_lcd_reset(void)
{
	/* DMA has to be disabled */
	lcdc_write(0, LCD_DMA_CTRL_REG);
	lcdc_write(0, LCD_RASTER_CTRL_REG);

	if (lcd_revision == LCD_VERSION_2) {
		lcdc_write(0, LCD_INT_ENABLE_SET_REG);
		/* Write 1 to reset */
		lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG);
		lcdc_write(0, LCD_CLK_RESET_REG);
	}
}

static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par,
					      unsigned lcdc_clk_div,
					      unsigned lcdc_clk_rate)
{
	int ret;

	if (par->lcdc_clk_rate != lcdc_clk_rate) {
		ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate);
		if (IS_ERR_VALUE(ret)) {
			dev_err(par->dev,
				"unable to set clock rate at %u\n",
				lcdc_clk_rate);
			return ret;
		}
		par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
	}

	/* Configure the LCD clock divisor. */
	lcdc_write(LCD_CLK_DIVISOR(lcdc_clk_div) |
			(LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);

	if (lcd_revision == LCD_VERSION_2)
		lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
				LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);

	return 0;
}

static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par,
					      unsigned pixclock,
					      unsigned *lcdc_clk_rate)
{
	unsigned lcdc_clk_div;

	pixclock = PICOS2KHZ(pixclock) * 1000;

	*lcdc_clk_rate = par->lcdc_clk_rate;

	if (pixclock < (*lcdc_clk_rate / CLK_MAX_DIV)) {
		*lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
						pixclock * CLK_MAX_DIV);
		lcdc_clk_div = CLK_MAX_DIV;
	} else if (pixclock > (*lcdc_clk_rate / CLK_MIN_DIV)) {
		*lcdc_clk_rate = clk_round_rate(par->lcdc_clk,
						pixclock * CLK_MIN_DIV);
		lcdc_clk_div = CLK_MIN_DIV;
	} else {
		lcdc_clk_div = *lcdc_clk_rate / pixclock;
	}

	return lcdc_clk_div;
}

static int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par,
					    struct fb_videomode *mode)
{
	unsigned lcdc_clk_rate;
	unsigned lcdc_clk_div = da8xx_fb_calc_clk_divider(par, mode->pixclock,
							  &lcdc_clk_rate);

	return da8xx_fb_config_clk_divider(par, lcdc_clk_div, lcdc_clk_rate);
}

static unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par,
					  unsigned pixclock)
{
	unsigned lcdc_clk_div, lcdc_clk_rate;

	lcdc_clk_div = da8xx_fb_calc_clk_divider(par, pixclock, &lcdc_clk_rate);
	return KHZ2PICOS(lcdc_clk_rate / (1000 * lcdc_clk_div));
}

static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
		struct fb_videomode *panel)
{
	u32 bpp;
	int ret = 0;

	ret = da8xx_fb_calc_config_clk_divider(par, panel);
	if (IS_ERR_VALUE(ret)) {
		dev_err(par->dev, "unable to configure clock\n");
		return ret;
	}

	if (panel->sync & FB_SYNC_CLK_INVERT)
		lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |
			LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);
	else
		lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) &
			~LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG);

	/* Configure the DMA burst size and fifo threshold. */
	ret = lcd_cfg_dma(cfg->dma_burst_sz, cfg->fifo_th);
	if (ret < 0)
		return ret;

	/* Configure the vertical and horizontal sync properties. */
	lcd_cfg_vertical_sync(panel->upper_margin, panel->vsync_len,
			panel->lower_margin);
	lcd_cfg_horizontal_sync(panel->left_margin, panel->hsync_len,
			panel->right_margin);

	/* Configure for disply */
	ret = lcd_cfg_display(cfg, panel);
	if (ret < 0)
		return ret;

	bpp = cfg->bpp;

	if (bpp == 12)
		bpp = 16;
	ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->xres,
				(unsigned int)panel->yres, bpp,
				cfg->raster_order);
	if (ret < 0)
		return ret;

	/* Configure FDD */
	lcdc_write((lcdc_read(LCD_RASTER_CTRL_REG) & 0xfff00fff) |
		       (cfg->fdd << 12), LCD_RASTER_CTRL_REG);

	return 0;
}

int register_vsync_cb(vsync_callback_t handler, void *arg, int idx)
{
	if ((vsync_cb_handler == NULL) && (vsync_cb_arg == NULL)) {
		vsync_cb_arg = arg;
		vsync_cb_handler = handler;
	} else {
		return -EEXIST;
	}

	return 0;
}
EXPORT_SYMBOL(register_vsync_cb);

int unregister_vsync_cb(vsync_callback_t handler, void *arg, int idx)
{
	if ((vsync_cb_handler == handler) && (vsync_cb_arg == arg)) {
		vsync_cb_handler = NULL;
		vsync_cb_arg = NULL;
	} else {
		return -ENXIO;
	}

	return 0;
}
EXPORT_SYMBOL(unregister_vsync_cb);

/* IRQ handler for version 2 of LCDC */
static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
{
	struct da8xx_fb_par *par = arg;
	u32 stat = lcdc_read(LCD_MASKED_STAT_REG);

	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
		lcd_disable_raster(DA8XX_FRAME_NOWAIT);
		lcdc_write(stat, LCD_MASKED_STAT_REG);
		lcd_enable_raster();
	} else if (stat & LCD_PL_LOAD_DONE) {
		/*
		 * Must disable raster before changing state of any control bit.
		 * And also must be disabled before clearing the PL loading
		 * interrupt via the following write to the status register. If
		 * this is done after then one gets multiple PL done interrupts.
		 */
		lcd_disable_raster(DA8XX_FRAME_NOWAIT);

		lcdc_write(stat, LCD_MASKED_STAT_REG);

		/* Disable PL completion interrupt */
		lcdc_write(LCD_V2_PL_INT_ENA, LCD_INT_ENABLE_CLR_REG);

		/* Setup and start data loading mode */
		lcd_blit(LOAD_DATA, par);
	} else {
		lcdc_write(stat, LCD_MASKED_STAT_REG);

		if (stat & LCD_END_OF_FRAME0) {
			par->which_dma_channel_done = 0;
			lcdc_write(par->dma_start,
				   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
			lcdc_write(par->dma_end,
				   LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
			par->vsync_flag = 1;
			wake_up_interruptible(&par->vsync_wait);
			if (vsync_cb_handler)
				vsync_cb_handler(vsync_cb_arg);
		}

		if (stat & LCD_END_OF_FRAME1) {
			par->which_dma_channel_done = 1;
			lcdc_write(par->dma_start,
				   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
			lcdc_write(par->dma_end,
				   LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
			par->vsync_flag = 1;
			wake_up_interruptible(&par->vsync_wait);
			if (vsync_cb_handler)
				vsync_cb_handler(vsync_cb_arg);
		}

		/* Set only when controller is disabled and at the end of
		 * active frame
		 */
		if (stat & BIT(0)) {
			frame_done_flag = 1;
			wake_up_interruptible(&frame_done_wq);
		}
	}

	lcdc_write(0, LCD_END_OF_INT_IND_REG);
	return IRQ_HANDLED;
}

/* IRQ handler for version 1 LCDC */
static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
{
	struct da8xx_fb_par *par = arg;
	u32 stat = lcdc_read(LCD_STAT_REG);
	u32 reg_ras;

	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
		lcd_disable_raster(DA8XX_FRAME_NOWAIT);
		lcdc_write(stat, LCD_STAT_REG);
		lcd_enable_raster();
	} else if (stat & LCD_PL_LOAD_DONE) {
		/*
		 * Must disable raster before changing state of any control bit.
		 * And also must be disabled before clearing the PL loading
		 * interrupt via the following write to the status register. If
		 * this is done after then one gets multiple PL done interrupts.
		 */
		lcd_disable_raster(DA8XX_FRAME_NOWAIT);

		lcdc_write(stat, LCD_STAT_REG);

		/* Disable PL completion inerrupt */
		reg_ras  = lcdc_read(LCD_RASTER_CTRL_REG);
		reg_ras &= ~LCD_V1_PL_INT_ENA;
		lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);

		/* Setup and start data loading mode */
		lcd_blit(LOAD_DATA, par);
	} else {
		lcdc_write(stat, LCD_STAT_REG);

		if (stat & LCD_END_OF_FRAME0) {
			par->which_dma_channel_done = 0;
			lcdc_write(par->dma_start,
				   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
			lcdc_write(par->dma_end,
				   LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
			par->vsync_flag = 1;
			wake_up_interruptible(&par->vsync_wait);
		}

		if (stat & LCD_END_OF_FRAME1) {
			par->which_dma_channel_done = 1;
			lcdc_write(par->dma_start,
				   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
			lcdc_write(par->dma_end,
				   LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
			par->vsync_flag = 1;
			wake_up_interruptible(&par->vsync_wait);
		}
	}

	return IRQ_HANDLED;
}

static int fb_check_var(struct fb_var_screeninfo *var,
			struct fb_info *info)
{
	int err = 0;
	struct da8xx_fb_par *par = info->par;
	int bpp = var->bits_per_pixel >> 3;
	unsigned long line_size = var->xres_virtual * bpp;

	if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1)
		return -EINVAL;

	switch (var->bits_per_pixel) {
	case 1:
	case 8:
		var->red.offset = 0;
		var->red.length = 8;
		var->green.offset = 0;
		var->green.length = 8;
		var->blue.offset = 0;
		var->blue.length = 8;
		var->transp.offset = 0;
		var->transp.length = 0;
		var->nonstd = 0;
		break;
	case 4:
		var->red.offset = 0;
		var->red.length = 4;
		var->green.offset = 0;
		var->green.length = 4;
		var->blue.offset = 0;
		var->blue.length = 4;
		var->transp.offset = 0;
		var->transp.length = 0;
		var->nonstd = FB_NONSTD_REV_PIX_IN_B;
		break;
	case 16:		/* RGB 565 */
		var->red.offset = 11;
		var->red.length = 5;
		var->green.offset = 5;
		var->green.length = 6;
		var->blue.offset = 0;
		var->blue.length = 5;
		var->transp.offset = 0;
		var->transp.length = 0;
		var->nonstd = 0;
		break;
	case 24:
		var->red.offset = 16;
		var->red.length = 8;
		var->green.offset = 8;
		var->green.length = 8;
		var->blue.offset = 0;
		var->blue.length = 8;
		var->nonstd = 0;
		break;
	case 32:
		var->transp.offset = 24;
		var->transp.length = 8;
		var->red.offset = 16;
		var->red.length = 8;
		var->green.offset = 8;
		var->green.length = 8;
		var->blue.offset = 0;
		var->blue.length = 8;
		var->nonstd = 0;
		break;
	default:
		err = -EINVAL;
	}

	var->red.msb_right = 0;
	var->green.msb_right = 0;
	var->blue.msb_right = 0;
	var->transp.msb_right = 0;

	if (line_size * var->yres_virtual > par->vram_size)
		var->yres_virtual = par->vram_size / line_size;

	if (var->yres > var->yres_virtual)
		var->yres = var->yres_virtual;

	if (var->xres > var->xres_virtual)
		var->xres = var->xres_virtual;

	if (var->xres + var->xoffset > var->xres_virtual)
		var->xoffset = var->xres_virtual - var->xres;
	if (var->yres + var->yoffset > var->yres_virtual)
		var->yoffset = var->yres_virtual - var->yres;

	var->pixclock = da8xx_fb_round_clk(par, var->pixclock);

	return err;
}

#ifdef CONFIG_CPU_FREQ
static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
				     unsigned long val, void *data)
{
	struct da8xx_fb_par *par;

	par = container_of(nb, struct da8xx_fb_par, freq_transition);
	if (val == CPUFREQ_POSTCHANGE) {
		if (par->lcdc_clk_rate != clk_get_rate(par->lcdc_clk)) {
			par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
			lcd_disable_raster(DA8XX_FRAME_WAIT);
			da8xx_fb_calc_config_clk_divider(par, &par->mode);
			if (par->blank == FB_BLANK_UNBLANK)
				lcd_enable_raster();
		}
	}

	return 0;
}

static int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par)
{
	par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition;

	return cpufreq_register_notifier(&par->freq_transition,
					 CPUFREQ_TRANSITION_NOTIFIER);
}

static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
{
	cpufreq_unregister_notifier(&par->freq_transition,
				    CPUFREQ_TRANSITION_NOTIFIER);
}
#endif

static int fb_remove(struct platform_device *dev)
{
	struct fb_info *info = dev_get_drvdata(&dev->dev);

	if (info) {
		struct da8xx_fb_par *par = info->par;

#ifdef CONFIG_CPU_FREQ
		lcd_da8xx_cpufreq_deregister(par);
#endif
		if (par->panel_power_ctrl)
			par->panel_power_ctrl(0);

		lcd_disable_raster(DA8XX_FRAME_WAIT);
		lcdc_write(0, LCD_RASTER_CTRL_REG);

		/* disable DMA  */
		lcdc_write(0, LCD_DMA_CTRL_REG);

		unregister_framebuffer(info);
		fb_dealloc_cmap(&info->cmap);
		dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
				  par->p_palette_base);
		dma_free_coherent(NULL, par->vram_size, par->vram_virt,
				  par->vram_phys);
		pm_runtime_put_sync(&dev->dev);
		pm_runtime_disable(&dev->dev);
		framebuffer_release(info);

	}
	return 0;
}

/*
 * Function to wait for vertical sync which for this LCD peripheral
 * translates into waiting for the current raster frame to complete.
 */
static int fb_wait_for_vsync(struct fb_info *info)
{
	struct da8xx_fb_par *par = info->par;
	int ret;

	/*
	 * Set flag to 0 and wait for isr to set to 1. It would seem there is a
	 * race condition here where the ISR could have occurred just before or
	 * just after this set. But since we are just coarsely waiting for
	 * a frame to complete then that's OK. i.e. if the frame completed
	 * just before this code executed then we have to wait another full
	 * frame time but there is no way to avoid such a situation. On the
	 * other hand if the frame completed just after then we don't need
	 * to wait long at all. Either way we are guaranteed to return to the
	 * user immediately after a frame completion which is all that is
	 * required.
	 */
	par->vsync_flag = 0;
	ret = wait_event_interruptible_timeout(par->vsync_wait,
					       par->vsync_flag != 0,
					       par->vsync_timeout);
	if (ret < 0)
		return ret;
	if (ret == 0)
		return -ETIMEDOUT;

	return 0;
}

static int fb_ioctl(struct fb_info *info, unsigned int cmd,
			  unsigned long arg)
{
	struct lcd_sync_arg sync_arg;

	switch (cmd) {
	case FBIOGET_CONTRAST:
	case FBIOPUT_CONTRAST:
	case FBIGET_BRIGHTNESS:
	case FBIPUT_BRIGHTNESS:
	case FBIGET_COLOR:
	case FBIPUT_COLOR:
		return -ENOTTY;
	case FBIPUT_HSYNC:
		if (copy_from_user(&sync_arg, (char *)arg,
				sizeof(struct lcd_sync_arg)))
			return -EFAULT;
		lcd_cfg_horizontal_sync(sync_arg.back_porch,
					sync_arg.pulse_width,
					sync_arg.front_porch);
		break;
	case FBIPUT_VSYNC:
		if (copy_from_user(&sync_arg, (char *)arg,
				sizeof(struct lcd_sync_arg)))
			return -EFAULT;
		lcd_cfg_vertical_sync(sync_arg.back_porch,
					sync_arg.pulse_width,
					sync_arg.front_porch);
		break;
	case FBIO_WAITFORVSYNC:
		return fb_wait_for_vsync(info);
	default:
		return -EINVAL;
	}
	return 0;
}

static int cfb_blank(int blank, struct fb_info *info)
{
	struct da8xx_fb_par *par = info->par;
	int ret = 0;

	if (par->blank == blank)
		return 0;

	par->blank = blank;
	switch (blank) {
	case FB_BLANK_UNBLANK:
		lcd_enable_raster();

		if (par->panel_power_ctrl)
			par->panel_power_ctrl(1);
		break;
	case FB_BLANK_NORMAL:
	case FB_BLANK_VSYNC_SUSPEND:
	case FB_BLANK_HSYNC_SUSPEND:
	case FB_BLANK_POWERDOWN:
		if (par->panel_power_ctrl)
			par->panel_power_ctrl(0);

		lcd_disable_raster(DA8XX_FRAME_WAIT);
		break;
	default:
		ret = -EINVAL;
	}

	return ret;
}

/*
 * Set new x,y offsets in the virtual display for the visible area and switch
 * to the new mode.
 */
static int da8xx_pan_display(struct fb_var_screeninfo *var,
			     struct fb_info *fbi)
{
	int ret = 0;
	struct fb_var_screeninfo new_var;
	struct da8xx_fb_par         *par = fbi->par;
	struct fb_fix_screeninfo    *fix = &fbi->fix;
	unsigned int end;
	unsigned int start;
	unsigned long irq_flags;

	if (var->xoffset != fbi->var.xoffset ||
			var->yoffset != fbi->var.yoffset) {
		memcpy(&new_var, &fbi->var, sizeof(new_var));
		new_var.xoffset = var->xoffset;
		new_var.yoffset = var->yoffset;
		if (fb_check_var(&new_var, fbi))
			ret = -EINVAL;
		else {
			memcpy(&fbi->var, &new_var, sizeof(new_var));

			start	= fix->smem_start +
				new_var.yoffset * fix->line_length +
				new_var.xoffset * fbi->var.bits_per_pixel / 8;
			end	= start + fbi->var.yres * fix->line_length - 1;
			par->dma_start	= start;
			par->dma_end	= end;
			spin_lock_irqsave(&par->lock_for_chan_update,
					irq_flags);
			if (par->which_dma_channel_done == 0) {
				lcdc_write(par->dma_start,
					   LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
				lcdc_write(par->dma_end,
					   LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
			} else if (par->which_dma_channel_done == 1) {
				lcdc_write(par->dma_start,
					   LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
				lcdc_write(par->dma_end,
					   LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
			}
			spin_unlock_irqrestore(&par->lock_for_chan_update,
					irq_flags);
		}
	}

	return ret;
}

static int da8xxfb_set_par(struct fb_info *info)
{
	struct da8xx_fb_par *par = info->par;
	int ret;
	bool raster = da8xx_fb_is_raster_enabled();

	if (raster)
		lcd_disable_raster(DA8XX_FRAME_WAIT);

	fb_var_to_videomode(&par->mode, &info->var);

	par->cfg.bpp = info->var.bits_per_pixel;

	info->fix.visual = (par->cfg.bpp <= 8) ?
				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
	info->fix.line_length = (par->mode.xres * par->cfg.bpp) / 8;

	ret = lcd_init(par, &par->cfg, &par->mode);
	if (ret < 0) {
		dev_err(par->dev, "lcd init failed\n");
		return ret;
	}

	par->dma_start = info->fix.smem_start +
			 info->var.yoffset * info->fix.line_length +
			 info->var.xoffset * info->var.bits_per_pixel / 8;
	par->dma_end   = par->dma_start +
			 info->var.yres * info->fix.line_length - 1;

	lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
	lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
	lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
	lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);

	if (raster)
		lcd_enable_raster();

	return 0;
}

static struct fb_ops da8xx_fb_ops = {
	.owner = THIS_MODULE,
	.fb_check_var = fb_check_var,
	.fb_set_par = da8xxfb_set_par,
	.fb_setcolreg = fb_setcolreg,
	.fb_pan_display = da8xx_pan_display,
	.fb_ioctl = fb_ioctl,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
	.fb_blank = cfb_blank,
};

static struct lcd_ctrl_config *da8xx_fb_create_cfg(struct platform_device *dev)
{
	struct lcd_ctrl_config *cfg;

	cfg = devm_kzalloc(&dev->dev, sizeof(struct fb_videomode), GFP_KERNEL);
	if (!cfg)
		return NULL;

	/* default values */

	if (lcd_revision == LCD_VERSION_1)
		cfg->bpp = 16;
	else
		cfg->bpp = 32;

	/*
	 * For panels so far used with this LCDC, below statement is sufficient.
	 * For new panels, if required, struct lcd_ctrl_cfg fields to be updated
	 * with additional/modified values. Those values would have to be then
	 * obtained from dt(requiring new dt bindings).
	 */

	cfg->panel_shade = COLOR_ACTIVE;

	return cfg;
}

static struct fb_videomode *da8xx_fb_get_videomode(struct platform_device *dev)
{
	struct da8xx_lcdc_platform_data *fb_pdata = dev_get_platdata(&dev->dev);
	struct fb_videomode *lcdc_info;
	struct device_node *np = dev->dev.of_node;
	int i;

	if (np) {
		lcdc_info = devm_kzalloc(&dev->dev,
					 sizeof(struct fb_videomode),
					 GFP_KERNEL);
		if (!lcdc_info)
			return NULL;

		if (of_get_fb_videomode(np, lcdc_info, OF_USE_NATIVE_MODE)) {
			dev_err(&dev->dev, "timings not available in DT\n");
			return NULL;
		}
		return lcdc_info;
	}

	for (i = 0, lcdc_info = known_lcd_panels;
		i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) {
		if (strcmp(fb_pdata->type, lcdc_info->name) == 0)
			break;
	}

	if (i == ARRAY_SIZE(known_lcd_panels)) {
		dev_err(&dev->dev, "no panel found\n");
		return NULL;
	}
	dev_info(&dev->dev, "found %s panel\n", lcdc_info->name);

	return lcdc_info;
}

static int fb_probe(struct platform_device *device)
{
	struct da8xx_lcdc_platform_data *fb_pdata =
						dev_get_platdata(&device->dev);
	static struct resource *lcdc_regs;
	struct lcd_ctrl_config *lcd_cfg;
	struct fb_videomode *lcdc_info;
	struct fb_info *da8xx_fb_info;
	struct da8xx_fb_par *par;
	struct clk *tmp_lcdc_clk;
	int ret;
	unsigned long ulcm;

	if (fb_pdata == NULL && !device->dev.of_node) {
		dev_err(&device->dev, "Can not get platform data\n");
		return -ENOENT;
	}

	lcdc_info = da8xx_fb_get_videomode(device);
	if (lcdc_info == NULL)
		return -ENODEV;

	lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0);
	da8xx_fb_reg_base = devm_ioremap_resource(&device->dev, lcdc_regs);
	if (IS_ERR(da8xx_fb_reg_base))
		return PTR_ERR(da8xx_fb_reg_base);

	tmp_lcdc_clk = devm_clk_get(&device->dev, "fck");
	if (IS_ERR(tmp_lcdc_clk)) {
		dev_err(&device->dev, "Can not get device clock\n");
		return PTR_ERR(tmp_lcdc_clk);
	}

	pm_runtime_enable(&device->dev);
	pm_runtime_get_sync(&device->dev);

	/* Determine LCD IP Version */
	switch (lcdc_read(LCD_PID_REG)) {
	case 0x4C100102:
		lcd_revision = LCD_VERSION_1;
		break;
	case 0x4F200800:
	case 0x4F201000:
		lcd_revision = LCD_VERSION_2;
		break;
	default:
		dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
				"defaulting to LCD revision 1\n",
				lcdc_read(LCD_PID_REG));
		lcd_revision = LCD_VERSION_1;
		break;
	}

	if (device->dev.of_node)
		lcd_cfg = da8xx_fb_create_cfg(device);
	else
		lcd_cfg = fb_pdata->controller_data;

	if (!lcd_cfg) {
		ret = -EINVAL;
		goto err_pm_runtime_disable;
	}

	da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par),
					&device->dev);
	if (!da8xx_fb_info) {
		dev_dbg(&device->dev, "Memory allocation failed for fb_info\n");
		ret = -ENOMEM;
		goto err_pm_runtime_disable;
	}

	par = da8xx_fb_info->par;
	par->dev = &device->dev;
	par->lcdc_clk = tmp_lcdc_clk;
	par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk);
	if (fb_pdata && fb_pdata->panel_power_ctrl) {
		par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
		par->panel_power_ctrl(1);
	}

	fb_videomode_to_var(&da8xx_fb_var, lcdc_info);
	par->cfg = *lcd_cfg;

	da8xx_fb_lcd_reset();

	/* allocate frame buffer */
	par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp;
	ulcm = lcm((lcdc_info->xres * lcd_cfg->bpp)/8, PAGE_SIZE);
	par->vram_size = roundup(par->vram_size/8, ulcm);
	par->vram_size = par->vram_size * LCD_NUM_BUFFERS;

	par->vram_virt = dma_alloc_coherent(NULL,
					    par->vram_size,
					    (resource_size_t *) &par->vram_phys,
					    GFP_KERNEL | GFP_DMA);
	if (!par->vram_virt) {
		dev_err(&device->dev,
			"GLCD: kmalloc for frame buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb;
	}

	da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt;
	da8xx_fb_fix.smem_start    = par->vram_phys;
	da8xx_fb_fix.smem_len      = par->vram_size;
	da8xx_fb_fix.line_length   = (lcdc_info->xres * lcd_cfg->bpp) / 8;

	par->dma_start = par->vram_phys;
	par->dma_end   = par->dma_start + lcdc_info->yres *
		da8xx_fb_fix.line_length - 1;

	/* allocate palette buffer */
	par->v_palette_base = dma_zalloc_coherent(NULL, PALETTE_SIZE,
						  (resource_size_t *)&par->p_palette_base,
						  GFP_KERNEL | GFP_DMA);
	if (!par->v_palette_base) {
		dev_err(&device->dev,
			"GLCD: kmalloc for palette buffer failed\n");
		ret = -EINVAL;
		goto err_release_fb_mem;
	}

	par->irq = platform_get_irq(device, 0);
	if (par->irq < 0) {
		ret = -ENOENT;
		goto err_release_pl_mem;
	}

	da8xx_fb_var.grayscale =
	    lcd_cfg->panel_shade == MONOCHROME ? 1 : 0;
	da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp;

	/* Initialize fbinfo */
	da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
	da8xx_fb_info->fix = da8xx_fb_fix;
	da8xx_fb_info->var = da8xx_fb_var;
	da8xx_fb_info->fbops = &da8xx_fb_ops;
	da8xx_fb_info->pseudo_palette = par->pseudo_palette;
	da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;

	ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
	if (ret)
		goto err_release_pl_mem;
	da8xx_fb_info->cmap.len = par->palette_sz;

	/* initialize var_screeninfo */
	da8xx_fb_var.activate = FB_ACTIVATE_FORCE;
	fb_set_var(da8xx_fb_info, &da8xx_fb_var);

	dev_set_drvdata(&device->dev, da8xx_fb_info);

	/* initialize the vsync wait queue */
	init_waitqueue_head(&par->vsync_wait);
	par->vsync_timeout = HZ / 5;
	par->which_dma_channel_done = -1;
	spin_lock_init(&par->lock_for_chan_update);

	/* Register the Frame Buffer  */
	if (register_framebuffer(da8xx_fb_info) < 0) {
		dev_err(&device->dev,
			"GLCD: Frame Buffer Registration Failed!\n");
		ret = -EINVAL;
		goto err_dealloc_cmap;
	}

#ifdef CONFIG_CPU_FREQ
	ret = lcd_da8xx_cpufreq_register(par);
	if (ret) {
		dev_err(&device->dev, "failed to register cpufreq\n");
		goto err_cpu_freq;
	}
#endif

	if (lcd_revision == LCD_VERSION_1){
		lcdc_irq_handler = lcdc_irq_handler_rev01;
		}
	else {
		init_waitqueue_head(&frame_done_wq);
		lcdc_irq_handler = lcdc_irq_handler_rev02;
	}

	ret = devm_request_irq(&device->dev, par->irq, lcdc_irq_handler, 0,
			       DRIVER_NAME, par);
	if (ret)
		goto irq_freq;
	return 0;

irq_freq:
#ifdef CONFIG_CPU_FREQ
	lcd_da8xx_cpufreq_deregister(par);
err_cpu_freq:
#endif
	unregister_framebuffer(da8xx_fb_info);

err_dealloc_cmap:
	fb_dealloc_cmap(&da8xx_fb_info->cmap);

err_release_pl_mem:
	dma_free_coherent(NULL, PALETTE_SIZE, par->v_palette_base,
			  par->p_palette_base);

err_release_fb_mem:
	dma_free_coherent(NULL, par->vram_size, par->vram_virt, par->vram_phys);

err_release_fb:
	framebuffer_release(da8xx_fb_info);

err_pm_runtime_disable:
	pm_runtime_put_sync(&device->dev);
	pm_runtime_disable(&device->dev);

	return ret;
}

#ifdef CONFIG_PM_SLEEP
static struct lcdc_context {
	u32 clk_enable;
	u32 ctrl;
	u32 dma_ctrl;
	u32 raster_timing_0;
	u32 raster_timing_1;
	u32 raster_timing_2;
	u32 int_enable_set;
	u32 dma_frm_buf_base_addr_0;
	u32 dma_frm_buf_ceiling_addr_0;
	u32 dma_frm_buf_base_addr_1;
	u32 dma_frm_buf_ceiling_addr_1;
	u32 raster_ctrl;
} reg_context;

static void lcd_context_save(void)
{
	if (lcd_revision == LCD_VERSION_2) {
		reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG);
		reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG);
	}

	reg_context.ctrl = lcdc_read(LCD_CTRL_REG);
	reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG);
	reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG);
	reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG);
	reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG);
	reg_context.dma_frm_buf_base_addr_0 =
		lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
	reg_context.dma_frm_buf_ceiling_addr_0 =
		lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
	reg_context.dma_frm_buf_base_addr_1 =
		lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
	reg_context.dma_frm_buf_ceiling_addr_1 =
		lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
	reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG);
	return;
}

static void lcd_context_restore(void)
{
	if (lcd_revision == LCD_VERSION_2) {
		lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG);
		lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG);
	}

	lcdc_write(reg_context.ctrl, LCD_CTRL_REG);
	lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG);
	lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG);
	lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG);
	lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG);
	lcdc_write(reg_context.dma_frm_buf_base_addr_0,
			LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
	lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0,
			LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
	lcdc_write(reg_context.dma_frm_buf_base_addr_1,
			LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
	lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1,
			LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
	lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG);
	return;
}

static int fb_suspend(struct device *dev)
{
	struct fb_info *info = dev_get_drvdata(dev);
	struct da8xx_fb_par *par = info->par;

	console_lock();
	if (par->panel_power_ctrl)
		par->panel_power_ctrl(0);

	fb_set_suspend(info, 1);
	lcd_disable_raster(DA8XX_FRAME_WAIT);
	lcd_context_save();
	pm_runtime_put_sync(dev);
	console_unlock();

	return 0;
}
static int fb_resume(struct device *dev)
{
	struct fb_info *info = dev_get_drvdata(dev);
	struct da8xx_fb_par *par = info->par;

	console_lock();
	pm_runtime_get_sync(dev);
	lcd_context_restore();
	if (par->blank == FB_BLANK_UNBLANK) {
		lcd_enable_raster();

		if (par->panel_power_ctrl)
			par->panel_power_ctrl(1);
	}

	fb_set_suspend(info, 0);
	console_unlock();

	return 0;
}
#endif

static SIMPLE_DEV_PM_OPS(fb_pm_ops, fb_suspend, fb_resume);

#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id da8xx_fb_of_match[] = {
	/*
	 * this driver supports version 1 and version 2 of the
	 * Texas Instruments lcd controller (lcdc) hardware block
	 */
	{.compatible = "ti,da8xx-tilcdc", },
	{.compatible = "ti,am33xx-tilcdc", },
	{},
};
MODULE_DEVICE_TABLE(of, da8xx_fb_of_match);
#endif

static struct platform_driver da8xx_fb_driver = {
	.probe = fb_probe,
	.remove = fb_remove,
	.driver = {
		   .name = DRIVER_NAME,
		   .of_match_table = of_match_ptr(da8xx_fb_of_match),
		   .pm	= &fb_pm_ops,
		   },
};
module_platform_driver(da8xx_fb_driver);

MODULE_DESCRIPTION("Framebuffer driver for TI da8xx/omap-l1xx");
MODULE_AUTHOR("Texas Instruments");
MODULE_LICENSE("GPL");

  • I will ask the software team to comment.
  • Hi,

    Which SDK is this?

    As I see from your dts file, you'd like to use the FBDEV, instead of DRM, right?  

    Did you do the appropriate defconfig modifications:

      add:  

               CONFIG_FB_DA8XX=y

               CONFIG_FB_DA8XX_TDA998X=y

      and remove:

               CONFIG_DRM=y

               CONFIG_DRM_I2C_NXP_TDA998X=y

               CONFIG_DRM_TILCDC=y

    Best Regards,

    Yordan

  • Hi,

    Which SDK is this?

    I am using ti-processor-sdk-linux-am335x-evm-02.00.01.07 which has linux kernel-4.1.13.

    As I see from your dts file, you'd like to use the FBDEV, instead of DRM, right? 

    Yes, i am using FBDEV driver(da8xx-fb.c).

    Only fbdev driver is enabled and panel information for da8xx-fb is given in .dts file.

    In am33xx.dtsi file:

    lcdc: lcdc@4830e000 {
                    //      compatible = "ti,am33xx-tilcdc";
                            compatible = "ti,da8xx-tilcdc";
                            reg = <0x4830e000 0x1000>;
                            interrupt-parent = <&intc>;
                            interrupts = <36>;
                            ti,hwmods = "lcdc";
                            status = "okay";
                    };

    In am335x-evmsk.dts file:

    &lcdc {
            status = "okay";
            pinctrl-names = "default","sleep";
            pinctrl-0 = <&lcd_pins_default>;
            pinctrl-1 = <&lcd_pins_sleep>;
            display-timings {
                    native-mode = <&timing0>;
                    timing0:320x240p16 {
                            hactive         = <320>;
                            vactive         = <240>;
                            hback-porch     = <68>;
                            hfront-porch    = <17>;
                            hsync-len       = <1>;
                            vback-porch     = <10>;
                            vfront-porch    = <7>;
                            vsync-len       = <2>;
                            clock-frequency = <6500000>;
                            hsync-active    = <0>;
                            vsync-active    = <0>;
                    };
            };

    In the above configurations, there is no option for setting .bpp.

    we completely disabled DRM related driver in .config file and also commented in .dts file

    Attached .config file for your reference.

    kindly guide us how to set bpp configuration?

    Thanks & Regards

    Geetha

    7317.config.txt

  • Have you tried adding the format in /etc/powervr.ini:
    DefaultPixelFormat=RGB565

    Also have track the lcd_version of your display in da8xx-fb.c. Also you could try hardcoding bpp in
    static struct lcd_ctrl_config *da8xx_fb_create_cfg(struct platform_device *dev)

    and have a look at the switch(bpp) statement in:
    static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
    u32 bpp, u32 raster_order)

    Best Regards,
    Yordan
  • Hi Yordan,

    Thanks for your replay,

    I am not using /etc/powervr.ini  

    In this lcd_vertion  2  is takeing. (in my display driver da8xx-fb.c).   

    I am added the below code and i got 16 bit bpp.

    In switch statement case 16  taking.    

    In /driver/video/fbdev/da8xx-fb.c

     static struct lcd_ctrl_config *da8xx_fb_create_cfg(struct platform_device *dev)

       {

           struct lcd_ctrl_config *cfg;

           struct device_node *np = dev->dev.of_node;

           cfg = devm_kzalloc(&dev->dev, sizeof(struct fb_videomode), GFP_KERNEL);

           if(!cfg) {

                                dev_err(&dev->dev, "memory allocation failed\n");

                                                       return NULL;
                                             }

                           if (lcd_revision == LCD_VERSION_1)

     
                         cfg->bpp = 16;

                          else {

                                             u32 val;

                                             if (!of_property_read_u32(np, "bpp", &val))

                                             cfg->bpp = val;

                                             else cfg->bpp = 16;

                                  }

           cfg->panel_shade = COLOR_ACTIVE;

          cfg->dma_burst_sz = 16;

          cfg->fifo_th = 6;

          return cfg;

    }

    In am335x-evmsk.dts file:

    &lcdc {

    status = "okay";

    pinctrl-names = "default","sleep";

    pinctrl-0 = <&lcd_pins_default>;

    pinctrl-1 = <&lcd_pins_sleep>;

    bpp = <16>;         

    ……

    The output of fbset command is:

    mode "320x240-76"

       # D: 8.000 MHz, H: 19.704 kHz, V: 76.079 Hz
        geometry 320 240 320 240 16
        timings 125000 68 17 10 7 1 2
        rgba 5/11,6/5,5/0,0/0
    endmode

    I did set the clock-frequency 6.5 MHz(  clock-frequency = <6500000>) in .dts file but its showing 8 MHz. why its changing?

    In this i am using default pin controls  but i changed  16 bit instead of 24 bit configuration. 

    How to configure Display LCD data lines in .dts file .I am not getting display.

    Please suggest us. 

     

     Thanks & Regards

    Geetha