1. 程式人生 > >Linux LCD驅動(一)——硬體分析和FrameBuffer

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、devicedevice_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命令學習 :touchmkdir 建立檔案資料夾

一、檢視命令詳情 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:把空行