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 ili9341 parallel kernel driver

Hi, 

I have obtained the ili9341 parallel kernel driver.

But, it is not the ti chip base.

Please tell me the define values for the following red color items.

######################################################################

/*
* ili9342 LCD for Raspberry Pi Model B rev2
*/

#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>


#define BLOCKSIZE (4*1024)

// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

#define DATA0 9
#define DATA1 11
#define DATA2 18
#define DATA3 23
#define DATA4 24
#define DATA5 25
#define DATA6 8
#define DATA7 7

#define DC 4
#define CS 27
#define RD 14
#define RW 15
#define IM0 10
#define RESET 17

#define ORIENTATION 0 //0=LANDSCAPE 1=PORTRAIT

#define DISPLAY_WIDTH 320
#define DISPLAY_HEIGHT 240

#define DISPLAY_BPP 16

volatile unsigned *gpio;


// Set to output
static void gpio_setoutput(char g)
{
INP_GPIO(g); // must use INP_GPIO before we can use OUT_GPIO
OUT_GPIO(g);
}

// Set state 1=high 0=low
static void gpio_setstate(char g,char state)
{
(state) ? (GPIO_SET = 1<<g) : (GPIO_CLR = 1<<g) ;
}


// initialization of GPIO
static void tft_init_board(struct fb_info *info)
{

gpio_setoutput(DATA0);
gpio_setoutput(DATA1);
gpio_setoutput(DATA2);
gpio_setoutput(DATA3);
gpio_setoutput(DATA4);
gpio_setoutput(DATA5);
gpio_setoutput(DATA6);
gpio_setoutput(DATA7);

gpio_setoutput(DC);
gpio_setoutput(CS);
gpio_setoutput(RD);
gpio_setoutput(RW);
gpio_setoutput(IM0);
gpio_setoutput(RESET);

gpio_setstate(DATA0,0);
gpio_setstate(DATA1,0);
gpio_setstate(DATA2,0);
gpio_setstate(DATA3,0);
gpio_setstate(DATA4,0);
gpio_setstate(DATA5,0);
gpio_setstate(DATA6,0);
gpio_setstate(DATA7,0);

gpio_setstate(DC,1);
gpio_setstate(CS,0);
gpio_setstate(RD,1);
gpio_setstate(RW,1);
gpio_setstate(IM0,1);
gpio_setstate(RESET,1);

}

// hard reset of the graphic controller and the tft
static void tft_hard_reset(void)
{
gpio_setstate(RESET,0);
msleep(120);
gpio_setstate(RESET,1);
msleep(120);
}

static void gpio_set_parallel_data(char data)
{
gpio_setstate(DATA0,((data >> 0) & 0x01));
gpio_setstate(DATA1,((data >> 1) & 0x01));
gpio_setstate(DATA2,((data >> 2) & 0x01));
gpio_setstate(DATA3,((data >> 3) & 0x01));
gpio_setstate(DATA4,((data >> 4) & 0x01));
gpio_setstate(DATA5,((data >> 5) & 0x01));
gpio_setstate(DATA6,((data >> 6) & 0x01));
gpio_setstate(DATA7,((data >> 7) & 0x01));
}

// write command
static void tft_command_write(char command)
{
gpio_setstate(DC,0);
gpio_set_parallel_data(command);
gpio_setstate(RW,0);
gpio_setstate(RW,1);
}

// write data
static void tft_data_write(char data)
{
gpio_setstate(DC,1);
gpio_set_parallel_data(data);
gpio_setstate(RW,0);
gpio_setstate(RW,1);
}

// initialization of ili9341
static void tft_init(struct fb_info *info)
{

tft_hard_reset();

tft_command_write(0x28); //display OFF
tft_command_write(0x11); //exit SLEEP mode
tft_data_write(0x00);
tft_command_write(0xCB); //Power Control A
tft_data_write(0x39); //always 0x39
tft_data_write(0x2C); //always 0x2C
tft_data_write(0x00); //always 0x
tft_data_write(0x34); //Vcore = 1.6V
tft_data_write(0x02); //DDVDH = 5.6V
tft_command_write(0xCF); //Power Control B
tft_data_write(0x00); //always 0x
tft_data_write(0x81); //PCEQ off
tft_data_write(0x30); //ESD protection
tft_command_write(0xE8); //Driver timing control A
tft_data_write(0x85); //non?overlap
tft_data_write(0x01); //EQ timing
tft_data_write(0x79); //Pre?charge timing
tft_command_write(0xEA); //Driver timing control B
tft_data_write(0x00); //Gate driver timing
tft_data_write(0x00); //always 0x
tft_command_write(0xED); //Power?On sequence control
tft_data_write(0x64); //soft start
tft_data_write(0x03); //power on sequence
tft_data_write(0x12); //power on sequence
tft_data_write(0x81); //DDVDH enhance on
tft_command_write(0xF7); //Pump ratio control
tft_data_write(0x20); //DDVDH=2xVCI
tft_command_write(0xC0); //power control 1
tft_data_write(0x26);
tft_data_write(0x04); //second parameter for ILI9340 (ignored by ILI9341)
tft_command_write(0xC1); //power control 2
tft_data_write(0x11);
tft_command_write(0xC5); //VCOM control 1
tft_data_write(0x35);
tft_data_write(0x3E);
tft_command_write(0xC7); //VCOM control 2
tft_data_write(0xBE);
tft_command_write(0x36); //memory access control = BGR
tft_data_write(0x88);
tft_command_write(0xB1); //frame rate control
tft_data_write(0x00);
tft_data_write(0x10);
tft_command_write(0xB6); //display function control
tft_data_write(0x0A);
tft_data_write(0xA2);
tft_command_write(0x3A); //pixel format = 16 bit per pixel
tft_data_write(0x55);
tft_command_write(0xF2); //3G Gamma control
tft_data_write(0x02); //off
tft_command_write(0x26); //Gamma curve 3
tft_data_write(0x01);
tft_command_write(0x2A); //column address set
tft_data_write(0x00);
tft_data_write(0x00); //start 0x00
tft_data_write(0x00);
tft_data_write(0xEF); //end 0xEF
tft_command_write(0x2B); //page address set
tft_data_write(0x00);
tft_data_write(0x00); //start 0x00
tft_data_write(0x01);
tft_data_write(0x3F); //end 0x013F

tft_command_write(0x29); //display ON

}

// write memory to TFT
static void ili9341_update_display_area(const struct fb_image *image)
{
int x,y;

// set column
(ORIENTATION) ? tft_command_write(0x2B) : tft_command_write(0x2A);

tft_data_write(image->dx >> 8);
tft_data_write(image->dx);

tft_data_write((image->dx + image->width) >> 8);
tft_data_write(image->dx + image->width);
// set row
(ORIENTATION) ? tft_command_write(0x2A) : tft_command_write(0x2B);

tft_data_write(image->dy >> 8);
tft_data_write(image->dy);

tft_data_write((image->dy + image->height) >> 8);
tft_data_write(image->dy + image->height);

tft_command_write(0x2C); //Memory Write

if(ORIENTATION == 0){
for(y=0;y < image->width ;y++){
for(x=0;x < image->height ;x++){
tft_data_write(image->data[(image->dx * (2 * image->width)) + (image->dy * 2) + 1]);
tft_data_write(image->data[(image->dx * (2 * image->width)) + (image->dy * 2) + 2]);
}
}
}else{
for(y=0;y < image->width ;y++){
for(x=0;x < image->height ;x++){
tft_data_write(image->data[(image->dx * (2 * image->width)) + (image->dy * 2) + 1]);
tft_data_write(image->data[(image->dx * (2 * image->width)) + (image->dy * 2) + 2]);
}
}
}

tft_command_write(0x29); //display ON
}


static void ili9341_update_display_color_area(const struct fb_fillrect *rect)
{
int x,y;
// set column
(ORIENTATION) ? tft_command_write(0x2B) : tft_command_write(0x2A);

tft_data_write(rect->dx >> 8);
tft_data_write(rect->dx);

tft_data_write((rect->dx + rect->width) >> 8);
tft_data_write(rect->dx + rect->width);
// set row

(ORIENTATION) ? tft_command_write(0x2A) : tft_command_write(0x2B);

tft_data_write(rect->dy >> 8);
tft_data_write(rect->dy);

tft_data_write((rect->dy + rect->height) >> 8);
tft_data_write(rect->dy + rect->height);

tft_command_write(0x2C); //Memory Write

if(ORIENTATION == 0){
for(y=0;y < rect->width ;y++){
for(x=0;x < rect->height ;x++){
tft_data_write(rect->color);
tft_data_write(rect->color >> 8);
}
}
}else{
for(y=0;y < rect->height ;y++){
for(x=0;x < rect->width ;x++){
tft_data_write(rect->color);
tft_data_write(rect->color >> 8);
}
}
}

tft_command_write(0x29); //display ON
}

static void ili9341_update_display(const struct fb_info *info)
{
int x,y;

tft_command_write(0x2C); //Memory Write

if(ORIENTATION == 0){
for(y=0;y < DISPLAY_WIDTH ;y++){
for(x=0;x < DISPLAY_HEIGHT ;x++){
tft_data_write(info->screen_base[(x * (2 * DISPLAY_WIDTH)) + (y * 2) + 1]);
tft_data_write(info->screen_base[(x * (2 * DISPLAY_WIDTH)) + (y * 2) + 2]);
}
}
}else{
for(y=(DISPLAY_HEIGHT - 1);y >= 0 ;y--){
for(x=0;x < DISPLAY_WIDTH ;x++){
tft_data_write(info->screen_base[(y * (2 * DISPLAY_WIDTH)) + (x * 2) + 1]);
tft_data_write(info->screen_base[(y * (2 * DISPLAY_WIDTH)) + (x * 2) + 2]);
}
}
}
tft_command_write(0x29); //display ON
}

static void ili9341_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
//printk(KERN_INFO "fb%d: ili9341_fillrect\n", info->node);
//ili9341_update_display_color_area(rect);
ili9341_update_display(info);
}

static void ili9341_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
//printk(KERN_INFO "fb%d: ili9341_copyarea\n", info->node);
ili9341_update_display(info);
}

static void ili9341_imageblit(struct fb_info *info, const struct fb_image *image)
{
//printk(KERN_INFO "fb%d: ili9341_imageblit\n", info->node);
//ili9341_update_display_area(image);
ili9341_update_display(info);
}

static ssize_t ili9341_write(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
void *dst;
int err = 0;
unsigned long total_size;

if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;

total_size = info->screen_size;

if (total_size == 0)
total_size = info->fix.smem_len;

if (p > total_size)
return -EFBIG;

if (count > total_size) {
err = -EFBIG;
count = total_size;
}

if (count + p > total_size) {
if (!err)
err = -ENOSPC;

count = total_size - p;
}

dst = (void __force *) (info->screen_base + p);

if (info->fbops->fb_sync)
info->fbops->fb_sync(info);

if (copy_from_user(dst, buf, count))
err = -EFAULT;

if (!err)
*ppos += count;

ili9341_update_display(info);

return (err) ? err : count;
}

static ssize_t ili9341_read(struct fb_info *info, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
void *dst;
int err = 0;
unsigned long total_size;

if (info->state != FBINFO_STATE_RUNNING)
return -EPERM;

total_size = info->screen_size;

if (total_size == 0)
total_size = info->fix.smem_len;

if (p > total_size)
return -EFBIG;

if (count > total_size) {
err = -EFBIG;
count = total_size;
}

if (count + p > total_size) {
if (!err)
err = -ENOSPC;

count = total_size - p;
}

dst = (void __force *) (info->screen_base + p);

if (info->fbops->fb_sync)
info->fbops->fb_sync(info);

if (copy_from_user(dst, buf, count))
err = -EFAULT;

if (!err)
*ppos += count;

return (err) ? err : count;
}

static void ili9341_deferred_io(struct fb_info *info, struct list_head *pagelist)
{
ili9341_update_display(info);
}

static struct fb_fix_screeninfo ili9341_fix = {
.id = "ili9341",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.accel = FB_ACCEL_NONE,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.line_length = DISPLAY_WIDTH * DISPLAY_BPP / 8,
};


static struct fb_var_screeninfo ili9341_var = {
.width = DISPLAY_WIDTH,
.height = DISPLAY_HEIGHT,
.bits_per_pixel = DISPLAY_BPP,
.xres = DISPLAY_WIDTH,
.yres = DISPLAY_HEIGHT,
.xres_virtual = DISPLAY_WIDTH,
.yres_virtual = DISPLAY_HEIGHT,
.activate = FB_ACTIVATE_NOW,
.vmode = FB_VMODE_NONINTERLACED,

.nonstd = 0,
.red.offset = 11,
.red.length = 5,
.green.offset = 5,
.green.length = 6,
.blue.offset = 0,
.blue.length = 5,
.transp.offset = 0,
.transp.length = 0,
};


static struct fb_ops ili9341_ops = {
.owner = THIS_MODULE,
.fb_read = ili9341_read,
.fb_write = ili9341_write,
.fb_fillrect = ili9341_fillrect,
.fb_copyarea = ili9341_copyarea,
.fb_imageblit = ili9341_imageblit,
};

static struct fb_deferred_io ili9341_defio = {
.delay = HZ/25,
.deferred_io = ili9341_deferred_io,
};

static unsigned int fps;


static int ili9341_probe(struct platform_device *pdev)
{
struct fb_info *info;
int retval = -ENOMEM;
int vmem_size;
unsigned char *vmem;


vmem_size = ili9341_var.width * ili9341_var.height * ili9341_var.bits_per_pixel/8;
vmem = vzalloc(vmem_size);
if (!vmem) {
return -ENOMEM;
}
memset(vmem, 0, vmem_size);


info = framebuffer_alloc(0, &pdev->dev);
if (!info) {
vfree(vmem);
return -ENOMEM;
}


info->screen_base = (char __force __iomem*)vmem;
info->fbops = &ili9341_ops;
info->fix = ili9341_fix;
info->fix.smem_start = (unsigned long)vmem;
info->fix.smem_len = vmem_size;
info->var = ili9341_var;
info->flags = FBINFO_DEFAULT | FBINFO_VIRTFB;

info->fbdefio = &ili9341_defio;
if (0 < fps) {
info->fbdefio->delay = HZ/fps;
}

fb_deferred_io_init(info);

retval = register_framebuffer(info);
if (retval < 0) {
framebuffer_release(info);
vfree(vmem);
return retval;
}

platform_set_drvdata(pdev, info);

gpio = ioremap(GPIO_BASE, BLOCKSIZE);

tft_init_board(info);
tft_hard_reset();
tft_init(info);

printk(KERN_INFO "fb%d: ili9341 LCD framebuffer device\n", info->node);
return 0;
}

static int ili9341_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);

if (info) {
unregister_framebuffer(info);
fb_deferred_io_cleanup(info);
vfree((void __force *)info->screen_base);

iounmap(gpio);


framebuffer_release(info);
}
return 0;
}


static struct platform_driver ili9341_driver = {
.probe = ili9341_probe,
.remove = ili9341_remove,
.driver = {
.name = "ili9341",
},
};

static struct platform_device *ili9341_device;

static int __init ili9341_init(void)
{
int ret = platform_driver_register(&ili9341_driver);
if (0 == ret) {
ili9341_device = platform_device_alloc("ili9341", 0);
if (ili9341_device) {
ret = platform_device_add(ili9341_device);
} else {
ret = -ENOMEM;
}
if (0 != ret) {
platform_device_put(ili9341_device);
platform_driver_unregister(&ili9341_driver);
}
}
return ret;
}

static void __exit ili9341_exit(void)
{
platform_device_unregister(ili9341_device);
platform_driver_unregister(&ili9341_driver);
}

module_param(fps, uint, 0);
MODULE_PARM_DESC(fps, "Frames per second (default 25)");

module_init(ili9341_init);
module_exit(ili9341_exit);

MODULE_DESCRIPTION("ili9341 LCD framebuffer driver");
MODULE_AUTHOR("sammyizimmy");
MODULE_LICENSE("GPL");

######################################################################

Here is my environment :

 - linux-3.14.26-g2489c02

lcdc_pins_default: my_lcdc_1_pins_default {
pinctrl-single,pins = <
0xe0 ( PIN_OUTPUT | MUX_MODE0 ) /* (U5) lcd_vsync.lcd_vsync */
0xe4 ( PIN_OUTPUT | MUX_MODE0 ) /* (R5) lcd_hsync.lcd_hsync */
0xe8 ( PIN_OUTPUT | MUX_MODE0 ) /* (V5) lcd_pclk.lcd_pclk */
0xa0 ( PIN_OUTPUT | MUX_MODE0 ) /* (R1) lcd_data0.lcd_data0 */
0xa4 ( PIN_OUTPUT | MUX_MODE0 ) /* (R2) lcd_data1.lcd_data1 */
0xa8 ( PIN_OUTPUT | MUX_MODE0 ) /* (R3) lcd_data2.lcd_data2 */
0xac ( PIN_OUTPUT | MUX_MODE0 ) /* (R4) lcd_data3.lcd_data3 */
0xb0 ( PIN_OUTPUT | MUX_MODE0 ) /* (T1) lcd_data4.lcd_data4 */
0xb4 ( PIN_OUTPUT | MUX_MODE0 ) /* (T2) lcd_data5.lcd_data5 */
0xb8 ( PIN_OUTPUT | MUX_MODE0 ) /* (T3) lcd_data6.lcd_data6 */
0xbc ( PIN_OUTPUT | MUX_MODE0 ) /* (T4) lcd_data7.lcd_data7 */
0xc0 ( PIN_OUTPUT | MUX_MODE0 ) /* (U1) lcd_data8.lcd_data8 */
0xc4 ( PIN_OUTPUT | MUX_MODE0 ) /* (U2) lcd_data9.lcd_data9 */
0xc8 ( PIN_OUTPUT | MUX_MODE0 ) /* (U3) lcd_data10.lcd_data10 */
0xcc ( PIN_OUTPUT | MUX_MODE0 ) /* (U4) lcd_data11.lcd_data11 */
0xd0 ( PIN_OUTPUT | MUX_MODE0 ) /* (V2) lcd_data12.lcd_data12 */
0xd4 ( PIN_OUTPUT | MUX_MODE0 ) /* (V3) lcd_data13.lcd_data13 */
0xd8 ( PIN_OUTPUT | MUX_MODE0 ) /* (V4) lcd_data14.lcd_data14 */
0xdc ( PIN_OUTPUT | MUX_MODE0 ) /* (T5) lcd_data15.lcd_data15 */
0xec ( PIN_OUTPUT | MUX_MODE0 ) /* (R6) lcd_ac_bias_en.lcd_ac_bias_en */
>;
};

  • Hi,

    This seems like it's based on GPIO bit-banging. The AM335X has an LCD controller, which is used in LIDD mode for driving displays with memory-type interface. However the current Linux SDK does not support this mode of operation. I'm afraid that you will need to develop your own LIDD mode driver.

    You can find information about LIDD mode in section 13 of the AM335X Technical Reference Manual Rev. L.