s3c2440液晶屏驱动 (非内核自带) linux-4.1.24

2023-09-01  

对于,不想逐一检查内核自带驱动,想自己编写驱动。

1,make menuconfig 去掉 编译到内核,改为 M 编译为 模块(因为要用到里面的3个.ko 驱动)

Device Drivers --->
    Graphics support --->
        Support for frame buffer devices --->
            S3C2410 LCD framebuffer support

 

2,make uImage && make modules 生成新内核  和 模块文件

烧写新内核或使用 nfs bootm 使用编译为 M 模块的内核启动。

复制 3个 ko 文件到 文件系统,这里用的是 NFS 网络文件系统。

cp drivers/video/fbdev/core/cfb*.ko /nfs_root/new_fs  (新的 4.1 内核是在这里,以前没有 这个 core 目录)

 

3, 使用原来的 2.6.22 的内核下的驱动程序,修改头文件后,编译为 .ko 文件放到 NFS 文件系统里,启动,如图所示

图忘拍了,有时是白屏,有时是竖的细彩线。

比较内核自带驱动 s3c2410fb.c 发现有个 usleep_range(1000, 1100); 

而原来的 2.6.22 的驱动里面,是没有启用 clk 的。添加上这部分后,重新编译,试机成功。


最后是完整的驱动源码:

  1 #include

  2 #include

  3 #include

  4 #include

  5 #include

  6 #include

  7 #include

  8 #include

  9 #include

 10 #include

 11 #include

 12 #include

 13 #include

 14 #include

 15 #include

 16 

 17 #include

 18 #include

 19 #include

 20 

 21 //#include

 22 //#include

 23 //#include

 24 //#include

 25 

 26 

 27 #include

 28 #include

 29 #include

 30 #include

 31 

 32 

 33 //参数定义

 34 #define LCD_WIDTH 480

 35 #define LCD_HEIGHT 272

 36 #define LCD_BIT 16

 37 

 38 #define LCD_CLKVAL 4

 39 #define LCD_TFT    3

 40 #define LCD_24BBP  0xd

 41 #define LCD_16BBP  0xc

 42 #define LCD_EN_OFF 0

 43 #define LCD_EN_ON  1

 44 #define LCD_VBPD   1

 45 #define LCD_LINEVAL  (LCD_HEIGHT - 1)

 46 #define LCD_VFPD   1

 47 #define LCD_VSPW   9

 48 #define LCD_HBPD   1

 49 #define LCD_HOZVAL (LCD_WIDTH - 1)

 50 #define LCD_HFPD   1

 51 #define LCD_HSPW   40

 52 #define LCD_INVVLINE 1

 53 #define LCD_INVVFRAME 1

 54 //调色板 u32 = unsigned int

 55 static u32 pseudo_palette[16];

 56 

 57 /* from pxafb.c */

 58 static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)

 59 {

 60     //只取16bit 数据

 61     chan &= 0xffff;

 62     //如 r = 16-5 = 11 : 右移去掉不要的位

 63     chan >>= (16 - bf->length);

 64     //在移到高位去 就是右边补0

 65     return chan << bf->offset;

 66 }

 67 

 68 static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red,

 69                  unsigned int green, unsigned int blue,

 70                  unsigned int transp, struct fb_info *info)

 71 {

 72     

 73     if(16 > regno)

 74     {

 75         unsigned int val;

 76         val  = chan_to_field(red, &info->var.red);

 77         val |= chan_to_field(green, &info->var.green);

 78         val |= chan_to_field(blue, &info->var.blue);

 79         pseudo_palette[regno] = val;

 80         return 0;

 81     }

 82     return 1;

 83 }

 84 

 85 

 86 static struct fb_ops s3c_ops = {

 87     .owner        = THIS_MODULE,

 88     .fb_setcolreg    = s3c_lcdfb_setcolreg,

 89     .fb_fillrect    = cfb_fillrect,

 90     .fb_copyarea    = cfb_copyarea,

 91     .fb_imageblit    = cfb_imageblit,

 92 };

 93 

 94 //定义GPIO

 95 static volatile unsigned long *gpb_con;

 96 static volatile unsigned long *gpc_con;

 97 static volatile unsigned long *gpd_con;

 98 static volatile unsigned long *gpg_con;

 99 

100 static volatile unsigned long *gpb_dat;

101 static volatile unsigned long *gpc_dat;

102 static volatile unsigned long *gpd_dat;

103 static volatile unsigned long *gpg_dat;

104 

105 struct lcd_regs {

106     unsigned long    lcdcon1;    

107     unsigned long    lcdcon2;    

108     unsigned long    lcdcon3;    

109     unsigned long    lcdcon4;    

110     unsigned long    lcdcon5;    

111     unsigned long    lcdsaddr1;    

112     unsigned long    lcdsaddr2;    

113     unsigned long    lcdsaddr3;    

114     unsigned long    redlut;    

115     unsigned long    greenlut;    

116     unsigned long    bluelut;    

117     unsigned long    reserved[9];    

118     unsigned long    dithmode;    

119     unsigned long    tpal;    

120     unsigned long    lcdintpnd;    

121     unsigned long    lcdsrcpnd;    

122     unsigned long    lcdintmsk;    

123     unsigned long    lpcsel;

124 };

125 

126 static volatile struct lcd_regs * lcd_reg;

127 

128 

129 //定义fb_info

130 static struct fb_info * s3c_lcd;

131 static int lcd_init(void)

132 {

133     //1,分配一个fb_info

134     s3c_lcd = framebuffer_alloc(0, NULL);

135 

136     struct clk *clk;    

137     clk = clk_get(NULL, "lcd");

138     if (IS_ERR(clk)) {

139         printk("failed to get lcd clock sourcen");

140     }

141 

142     clk_prepare_enable(clk);

143     printk("got and enabled clockn");

144 

145     usleep_range(1000, 1100);

146     

147     //2,设置

148     //2,1 设置固定的参数

149     strcpy(s3c_lcd->fix.id, "mylcd");

150     s3c_lcd->fix.smem_len  = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;

151     s3c_lcd->fix.type        = FB_TYPE_PACKED_PIXELS;

152     s3c_lcd->fix.visual      = FB_VISUAL_TRUECOLOR;

153     s3c_lcd->fix.line_length = LCD_WIDTH * LCD_BIT / 8; //单位 bytes    

154     //物理地址由 dma_alloc_writecombine 函数分配

155     //s3c_lcd->fix.smem_start  = LCD_FRAMEBUFFER;

156     //s3c_lcd->fix.mmio_len    = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;

157     

158     //2,2 设置可变的参数

159     s3c_lcd->var.width  = LCD_WIDTH;

160     s3c_lcd->var.height = LCD_HEIGHT;

161     s3c_lcd->var.xres         = LCD_WIDTH;

162     s3c_lcd->var.yres         = LCD_HEIGHT;

163     s3c_lcd->var.xres_virtual = LCD_WIDTH;

164     s3c_lcd->var.yres_virtual = LCD_HEIGHT;

165     s3c_lcd->var.bits_per_pixel = LCD_BIT;

166     //RGB 5 6 5

167     s3c_lcd->var.red.length   = 5;

168     s3c_lcd->var.red.offset   = 11;

169     s3c_lcd->var.green.length = 6;

170     s3c_lcd->var.green.offset = 5;

171     s3c_lcd->var.blue.length  = 5;

172     s3c_lcd->var.blue.offset  = 0;

173     s3c_lcd->var.activate     = FB_ACTIVATE_NOW;

174 

175     s3c_lcd->var.pixclock = 100000;

176 

177     //2,3 设置操作函数

178     s3c_lcd->fbops = &s3c_ops;

179 

180     //2.4 其它的设置

181     s3c_lcd->screen_size = LCD_WIDTH * LCD_HEIGHT * LCD_BIT / 8;

182     s3c_lcd->pseudo_palette = pseudo_palette;

183     

184     //3,硬件相关的操作

185     //3,1 配置GPIO

186     gpb_con = ioremap(0x56000010, 4);

187     gpb_dat = gpb_con + 1;

188 

189     gpc_con = ioremap(0x56000020, 4);

190     gpc_dat = gpc_con + 1;

191 

192     gpd_con = ioremap(0x56000030, 4);

193     gpc_dat = gpd_con + 1;

194 

195     gpg_con = ioremap(0x56000060, 4);

196     gpg_dat = gpg_con + 1;

197 

198     *gpc_con = 0xaaaaaaaa;   // GPIO管脚用于VD[7:0],LCDVF[2:0],VM,VFRAME,VLINE,VCLK,LEND 

199     *gpd_con = 0xaaaaaaaa;   // GPIO管脚用于VD[23:8]

200 

201     *gpb_con &= ~(3);        //配置背光引脚为输出

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。