Linux LCD驅動(一)——硬體分析和FrameBuffer
* Hz -> picoseconds is / 10^-12
*/
unsigned long long div = (unsigned long long)clk * pixclk;
div >>= 12; /* div / 2^12 */
do_div(div, 625 * 625UL * 625); /* div / 5^12, do_div巨集定義在asm/div64.h中*/
return div;
}
/*根據資料手冊按照TFT屏的要求配置LCD控制暫存器1-5*/
static void my2440fb_config_tft_lcd_regs(const struct fb_info *fbinfo, struct s3c2410fb_hw *regs)
{
const struct my2440fb_var *fbvar = fbinfo->par;
const struct fb_var_screeninfo *var = &fbinfo->var;
/*根據色位模式設定LCD控制暫存器1和5,參考資料手冊*/
switch (var->bits_per_pixel)
{
case 1:/*1BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
break;
case 2:/*2BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
break;
case 4:/*4BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
break
case 8:/*8BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
regs->lcdcon5 |= S3C2410_LCDCON5_BSWP | S3C2410_LCDCON5_FRM565;
regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;
break;
case 16:/*16BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;
regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;
break;
case 32:/*32BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;
regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP | S3C2410_LCDCON5_HWSWP | S3C2410_LCDCON5_BPP24BL);
break;
default:/*無效的BPP*/
dev_err(fbvar->dev, "invalid bpp %d/n", var->bits_per_pixel);
}
/*設定LCD配置暫存器2、3、4*/
regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
S3C2410_LCDCON2_VSPW(var->vsync_len - 1);
regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
S3C2410_LCDCON3_HOZVAL(var->xres - 1);
regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
}
/*根據資料手冊按照STN屏的要求配置LCD控制暫存器1-5*/
static void my2440fb_config_stn_lcd_regs(const struct fb_info *fbinfo, struct s3c2410fb_hw *regs)
{
const struct my2440fb_var *fbvar = fbinfo->par;
const struct fb_var_screeninfo *var = &fbinfo->var;
int type = regs->lcdcon1 & ~S3C2410_LCDCON1_TFT;
int hs = var->xres >> 2;
unsigned wdly = (var->left_margin >> 4) - 1;
unsigned wlh = (var->hsync_len >> 4) - 1;
if (type != S3C2410_LCDCON1_STN4)
{
hs >>= 1;
}
/*根據色位模式設定LCD控制暫存器1,參考資料手冊*/
switch (var->bits_per_pixel)
{
case 1:/*1BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_STN1BPP;
break;
case 2:/*2BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_STN2GREY;
break;
case 4:/*4BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_STN4GREY;
break;
case 8:/*8BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_STN8BPP;
hs *= 3;
break;
case 12:/*12BPP*/
regs->lcdcon1 |= S3C2410_LCDCON1_STN12BPP;
hs *= 3;
break;
default:/*無效的BPP*/
dev_err(fbvar->dev, "invalid bpp %d/n", var->bits_per_pixel);
}
/*設定LCD配置暫存器2、3、4, 參考資料手冊*/
if (wdly > 3) wdly = 3;
if (wlh > 3) wlh = 3;
regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1);
regs->lcdcon3 = S3C2410_LCDCON3_WDLY(wdly) |
S3C2410_LCDCON3_LINEBLANK(var->right_margin / 8) |
S3C2410_LCDCON3_HOZVAL(hs - 1);
regs->lcdcon4 = S3C2410_LCDCON4_WLH(wlh);
}
/*配置幀緩衝起始地址暫存器1-3,參考資料手冊*/
static void my2440fb_set_lcdaddr(struct fb_info *fbinfo)
{
unsigned long saddr1, saddr2, saddr3;
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
saddr1 = fbinfo->fix.smem_start >> 1;
saddr2 = fbinfo->fix.smem_start;
saddr2 += fbinfo->fix.line_length * fbinfo->var.yres;
saddr2 >>= 1;
saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((fbinfo->fix.line_length / 2) & 0x3ff);
writel(saddr1, regs + S3C2410_LCDSADDR1);
writel(saddr2, regs + S3C2410_LCDSADDR2);
writel(saddr3, regs + S3C2410_LCDSADDR3);
}
/*顯示空白,blank mode有5種模式,定義在fb.h中,是一個列舉*/
static int my2440fb_blank(int blank_mode, struct fb_info *fbinfo)
{
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
/*根據顯示空白的模式來設定LCD是開啟還是停止*/
if (blank_mode == FB_BLANK_POWERDOWN)
{
my2440fb_lcd_enable(fbvar, 0);/*在第②步中定義*/
}
else
{
my2440fb_lcd_enable(fbvar, 1);/*在第②步中定義*/
}
/*根據顯示空白的模式來控制臨時調色盤暫存器*/
if (blank_mode == FB_BLANK_UNBLANK)
{
/*臨時調色盤暫存器無效*/
writel(0x0, regs + S3C2410_TPAL);
}
else
{
/*臨時調色盤暫存器有效*/
writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL);
}
return 0;
}
/*設定顏色表*/
static int my2440fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info *fbinfo)
{
unsigned int val;
struct my2440fb_var *fbvar = fbinfo->par;
void __iomem *regs = fbvar->lcd_base;
switch (fbinfo->fix.visual)
{
case FB_VISUAL_TRUECOLOR:
/*真彩色*/
if (regno < 16)
{
u32 *pal = fbinfo->pseudo_palette;
val = chan_to_field(red, &fbinfo->var.red);
val |= chan_to_field(green, &fbinfo->var.green);
val |= chan_to_field(blue, &fbinfo->var.blue);
pal[regno] = val;
}
break;
case FB_VISUAL_PSEUDOCOLOR:
/*偽彩色*/
if (regno < 256)
{
val = (red >> 0) & 0xf800;
val |= (green >> 5) & 0x07e0;
val |= (blue >> 11) & 0x001f;
writel(val, regs + S3C2410_TFTPAL(regno));
/*修改調色盤*/
schedule_palette_update(fbvar, regno, val);
}
break;
default:
return 1;
}
return 0;
}
static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf)
{
chan &= 0xffff;
chan >>= 16 - bf->length;
return chan << bf->offset;
}
/*修改調色盤*/
static void schedule_palette_update(struct my2440fb_var *fbvar, unsigned int regno, unsigned int val)
{
unsigned long flags;
unsigned long irqen;
/*LCD中斷掛起暫存器基地址*/
void __iomem *lcd_irq_base = fbvar->lcd_base + S3C2410_LCDINTBASE;
/*在修改中斷暫存器值之前先遮蔽中斷,將中斷狀態儲存到flags中*/
local_irq_save(flags);
fbvar->palette_buffer[regno] = val;
/*判斷調色盤是否準備就像*/
if (!fbvar->palette_ready)
{
fbvar->palette_ready = 1;
/*使能中斷遮蔽暫存器*/
irqen = readl(lcd_irq_base + S3C24XX_LCDINTMSK);
irqen &= ~S3C2410_LCDINT_FRSYNC;
writel(irqen, lcd_irq_base + S3C24XX_LCDINTMSK);
}
/*恢復被遮蔽的中斷*/
local_irq_restore(flags);
}
相關推薦
Linux LCD驅動(一)——硬體分析和FrameBuffer
/* 畫素時鐘單位是皮秒,而時鐘的單位是赫茲,所以計算公式為: * Hz -> picoseconds is / 10^-12 */ unsigned long long div = (unsigned long long)clk * pixclk;
S3C2440 linux LCD驅動分析
環境: 硬體平臺 TQ2440 東華3.5 inch TFT LCD
10. LCD驅動程式 ——框架分析 第017課 LCD原理詳解及裸機程式分析 15.linux-LCD層次分析(詳解)
引言: 由LCD的硬體原理及操作(可參看韋哥部落格:第017課 LCD原理詳解及裸機程式分析) 我們知道只要LCD控制器的相關暫存器正確配置好,就可以在LCD面板上顯示framebuffer中的內容。 若應用程式需要在LCD螢幕上顯示文字或影象時,只需要把相應的顯示內容以正確的格式寫到Framebuff
linux裝置驅動模型架構分析 一
概述LDD3中說:“Linux核心需要一個對系統結構的一般性描述。”這個描述就是linux裝置驅動模型(下面簡稱為LDDM)。LDDM不是獨立存在,其體系如下圖所示:對架構的每一部分本文都會開闢獨立的章節進行描述。暫且拋開這個架構,首先從總體上了解一下LDDM。LDDM與驅動
Linux裝置驅動模型框架分析(三)——LDDM的實體bus_type、device和device_driver
在Linux裝置模型中,Bus(匯流排)是一類特殊的裝置,它是連線處理器和其它裝置之間的通道(channel)。為了方便裝置模型的實現,核心規定,系統中的每個裝置都要連線在一個Bus上,這個Bus可以是一個內部Bus、虛擬Bus或者Platform Bus。 device
《Linux驅動》iTop4412開發板LCD驅動 詳細分析 (三)
接下來我們來詳解介紹probe中的函式: 第一個函式: s3cfb_set_lcd_info(fbdev[i]); 1.該函式原始碼如下: /*該函式在s3cfb_wa101s.c 中*/ /* name should be fixed as
linux裝置驅動模型架構分析(一)——概述
概述 LDD3中說:“Linux核心需要一個對系統結構的一般性描述。”這個描述就是linux裝置驅動模型(下面簡稱為LDDM)。LDDM不是獨立存在,其體系如下圖所示: LDDM體系結構 對架構的每一部分本文都會開闢獨立的章節進行描述。暫且拋開這個架構,首先從總體上了
Linux Kernel系列一:開篇和Kernel啟動概要
mis misc 跳轉 line global 最終 width lin 通過 前言 最近幾個月將Linux Kernel的大概研究了一下,下面需要進行深入詳細的分析。主要將以S3C2440的一塊開發板為硬件實體。大概包括如下內容: 1 bootloader分析,以uboo
linux裝置驅動開發學習--記憶體和IO訪問
一 I/O 埠 1. 讀寫位元組埠(8 位寬) unsigned inb(unsigned port); void outb(unsigned char byte, unsigned port); 2. 讀寫字埠(16 位寬) unsigned inw(unsigne
10. LCD驅動程序 ——框架分析
指針 mas 會有 因此 == ngs 數據結構 寄存器 char 引言: 由LCD的硬件原理及操作(可參看韋哥博客:第017課 LCD原理詳解及裸機程序分析) 我們知道只要LCD控制器的相關寄存器正確配置好,就可以在LCD面板上顯示framebuffer中的內容。 若應用
Linux裝置驅動程式架構分析之一個I2C驅動例項
作者:劉昊昱 核心版本:3.10.1 編寫一個I2C裝置驅動程式的工作可分為兩部分,一是定義和註冊I2C裝置,即i2c_client;二是定義和註冊I2C裝置驅動,即i2c_driver。下面我們就以mini2440的I2C裝置at24c08 EEPROM為例,介紹如
Linux裝置驅動程式架構分析之I2C架構(基於3.10.1核心)
作者:劉昊昱 核心版本:3.10.1 I2C體系架構的硬體實體包括兩部分: 硬體I2C Adapter:硬體I2C Adapter表示一個硬體I2C介面卡,也就是I2C控制器。一般是SOC中的一個介面,也可以用GPIO模擬。硬體I2C Adapter主要用來在I2
深入淺出:Linux裝置驅動中的阻塞和非阻塞I/O
今天寫的是Linux裝置驅動中的阻塞和非阻塞I/0,何謂阻塞與非阻塞I/O?簡單來說就是對I/O操作的兩種不同的方式,驅動程式可以靈活的支援使用者空間對裝置的這兩種訪問方式。 一、基本概念: 阻塞操作 : 是指在執行裝置操作時,若不能獲得資源,則掛起程序直到
Linux裝置驅動程式架構分析之SD Spec摘要
作者:劉昊昱 本文是對SDSpecifications Part 1 Physical Layer Simplified Specification Version 4.10的摘要記錄,具體資訊可參考該文件。 3、SD Memory Card System Conc
Linux裝置驅動程式架構分析之MMC/SD(二)
作者:劉昊昱 核心版本:3.10.1 一、s3cmci_ops分析 在上一篇文章中我們分析了Mini2440 MMC/SD驅動的probe函式s3cmci_probe。在該函式中初始化了struct mmc_host指標變數mmc,其中,設定mmc->ops為s
Android冷啟動白屏解析,帶你一步步分析和解決問題
本文同步發表於我的微信公眾號,掃一掃文章底部的二維碼或在微信搜尋 郭霖 即可關注,每天都有文章更新。 寫在前面 記得在本月初,我發表了一篇文章叫《 Android Studio新功能解析,你真的瞭解Instant Run嗎?》,裡面詳細講解了
Linux裝置驅動程式架構分析之platform(基於3.10.1核心)
作者:劉昊昱 核心版本:3.10.1 一、platform bus的註冊 platform bus註冊是通過platform_bus_init函式完成的,該函式定義在drivers/base/platform.c檔案中,其內容如下: 904int __init pl
linux——LCD驅動
轉載fbmem分析 實現步驟 定義、分配fb_info* static struct fb_info *s3c_lcd; s3c_lcd = framebuffer_alloc(0, NULL); 設定s3c_lcd* 硬體相關的操作* 配置GPIO用於
linux命令學習一 :touch和mkdir 建立檔案和資料夾
一、檢視命令詳情 touch --help mkdir --help 二、常用命令 1、建立檔案: touch filename 2、建立資料夾:mkdir directoryname 可建立父資料夾或建立多個或建立多級資料夾 mkdir -
Linux計算某一列的和
inux 說明 awk linu egrep gre d+ div span ll | awk ‘{print $5}‘ | egrep -v "^$"| paste -sd+|bc 簡單說明: ll:拿到當前目錄下所有的文件大小 awk:拿到第幾列 egrep:把空行