1. 程式人生 > >UBOOT——MMC驅動分析

UBOOT——MMC驅動分析

1:MMC驅動初始化是在start_armboot函式中

#if defined(CONFIG_X210)

    #if defined(CONFIG_GENERIC_MMC)
        puts ("SD/MMC: ");
        ///* //lqm masked
        mmc_exist = mmc_initialize(gd->bd);
        if (mmc_exist != 0)
        {
            puts ("0 MB\n");
        }
        //*/
    #endif

    
    #if defined(CONFIG_CMD_NAND)
        puts(
"NAND: "); nand_init(); #endif #endif /* CONFIG_X210 */
實際上是呼叫了 mmc_initialize(gd->bd);這個函式來進行初始化的
struct mmc *mmc;
這裡定義了一個struct mmc型別的結構體指標;這個struct mmc型別的結構體非常重要,
我們說的驅動主要就是構建這個結構體;
在這個結構體中構建了一些列變數、函式指標等;這些變數記錄了mmc的一些資訊,函式指標所指向的函式是
用來向sd卡中傳送命令、或者傳送資料、直接操作最底層的特殊功能暫存器;
 1 struct mmc {
2 struct list_head link; 3 char name[32]; 4 void *priv; 5 uint voltages; 6 uint version; 7 uint f_min; 8 uint f_max; 9 int high_capacity; 10 uint bus_width; 11 uint clock; 12 uint card_caps; 13 uint host_caps; 14 uint ocr; 15 uint scr[2];
16 uint csd[4]; 17 uint cid[4]; 18 ushort rca; 19 uint tran_speed; 20 uint read_bl_len; 21 uint write_bl_len; 22 u32 capacity; 23 struct mmc_ext_csd ext_csd; /* mmc v4 extended card specific */ 24 block_dev_desc_t block_dev; 25 int (*send_cmd)(struct mmc *mmc, 26 struct mmc_cmd *cmd, struct mmc_data *data); 27 void (*set_ios)(struct mmc *mmc); 28 int (*init)(struct mmc *mmc); 29 };
接下來就是cpu_mmc_init(bis);這個函式:
 1 int cpu_mmc_init(bd_t *bis)
 2 {
 3 #ifdef CONFIG_S3C_HSMMC
 4     setup_hsmmc_clock();
 5     setup_hsmmc_cfg_gpio();
 6     return smdk_s3c_hsmmc_init();
 7 #else
 8     return 0;
 9 #endif
10 }
這個函式的作用是把mmc與Soc相關的初始化工作完成了;
mmc的初始化化分兩個部分
  (1)與SoC有關的部分包括:初始化時鐘、初始化相關GPIO、初始化與SoC有關的mmc控制器;
  (2)與外部sd卡有關的部分:初始化mmc卡中的晶片控制器等;
第一部分的mmc時鐘初始化以及gpio初始化我們放在cpu_s5pc11x資料夾;
與SoC有關的控制器放在drivers/mmc資料夾下;
與mmc內部控制器有關的初始化函式為mmc_init,這個函式也在
drivers/mmc資料夾下;
上面幾點表面:關於mmc的驅動是分離的,時鐘、GPIO一部分;SoC內部控制器一部分;SoC外部控制器一部分;
這樣做的一個好處就是減輕移植程式碼的大量工作;比如說mmc沒有變,而更換了一個SoC,我們只需要更改SoC相關
的那一部分程式碼即可,同樣SoC沒有變而mmc卡變了,我們則只需要更改mmc卡相關的那部分初始化程式碼即可;
下面我們來詳細看一下這些初始化函式
setup_hsmmc_clock:
選擇時鐘源、分頻
 1 void setup_hsmmc_clock(void)
 2 {
 3     u32 tmp;
 4     u32 clock;
 5     u32 i;
 6 
 7     /* MMC0 clock src = SCLKMPLL */
 8     tmp = CLK_SRC4_REG & ~(0x0000000f);
 9     CLK_SRC4_REG = tmp | 0x00000006;
10 
11     /* MMC0 clock div */
12     tmp = CLK_DIV4_REG & ~(0x0000000f);
13     clock = get_MPLL_CLK()/1000000;
14     for(i=0; i<0xf; i++)
15     {
16         if((clock / (i+1)) <= 52) {
17             CLK_DIV4_REG = tmp | i<<0;
18             break;
19         }
20     }
21 
22 #ifdef USE_MMC1
23     /* MMC1 clock src = SCLKMPLL */
24     tmp = CLK_SRC4_REG & ~(0x000000f0);
25     CLK_SRC4_REG = tmp | 0x00000060;
26 
27     /* MMC1 clock div */
28     tmp = CLK_DIV4_REG & ~(0x000000f0);
29     CLK_DIV4_REG = tmp | i<<4;
30 #endif    
31 
32 #ifdef USE_MMC2
33     /* MMC2 clock src = SCLKMPLL */
34     tmp = CLK_SRC4_REG & ~(0x00000f00);
35     CLK_SRC4_REG = tmp | 0x00000600;
36 
37     /* MMC2 clock div */
38     tmp = CLK_DIV4_REG & ~(0x00000f00);
39     CLK_DIV4_REG = tmp | i<<8;
40 #endif
41 
42 #ifdef USE_MMC3
43     /* MMC3 clock src = SCLKMPLL */
44     tmp = CLK_SRC4_REG & ~(0x00000f00);
45     CLK_SRC4_REG = tmp | 0x00000600;
46 
47     /* MMC3 clock div */
48     tmp = CLK_DIV4_REG & ~(0x00000f00);
49     CLK_DIV4_REG = tmp | i<<12;
50 #endif    
51 }

setup_hsmmc_cfg_gpio:初始化相關GPIO可以對資料手冊來看比較簡單;

 1 void setup_hsmmc_cfg_gpio(void)
 2 {
 3     ulong reg;
 4 
 5     /* MMC channel 0 */
 6     /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */
 7     reg = readl(GPG0CON) & 0xf0000000;
 8     writel(reg | 0x02222222, GPG0CON);
 9     reg = readl(GPG0PUD) & 0xffffc000;
10     writel(reg | 0x00002aaa, GPG0PUD);
11     writel(0x00003fff, GPG0DRV);
12 #ifdef USE_MMC0_8BIT
13     reg = readl(GPG1CON) & 0xf0000fff;
14     writel(reg | 0x03333000, GPG1CON);
15     reg = readl(GPG1PUD) & 0xffffc03f;
16     writel(reg | 0x00002a80, GPG1PUD);
17     writel(0x00003fc0, GPG1DRV);
18 #endif
19 
20 #ifdef USE_MMC1
21     /* MMC channel 1 */
22     /* 7 pins will be assigned - GPG1[0:6] = CLK, CMD, CDn, DAT[0:3] */
23     reg = readl(GPG1CON) & 0xf0000000;
24     writel(reg | 0x02222222, GPG1CON);
25     reg = readl(GPG1PUD) & 0xffffc000;
26     writel(reg | 0x00002aaa, GPG1PUD);
27     writel(0x00003fff, GPG1DRV);
28 #endif
29 
30 #ifdef USE_MMC2
31     /* MMC channel 2 */
32     /* 7 pins will be assigned - GPG2[0:6] = CLK, CMD, CDn, DAT[0:3] */
33     reg = readl(GPG2CON) & 0xf0000000;
34     writel(reg | 0x02222222, GPG2CON);
35     reg = readl(GPG2PUD) & 0xffffc000;
36     writel(reg | 0x00002aaa, GPG2PUD);
37     writel(0x00003fff, GPG2DRV);
38 #ifdef USE_MMC2_8BIT
39     /* 4 pins will be assigned - GPG3[3:6] = DAT[4:7] */
40     reg = readl(GPG3CON) & 0xf0000fff;
41     writel(reg | 0x03333000, GPG3CON);
42     reg = readl(GPG3PUD) & 0xffffc03f;
43     writel(reg | 0x00002a80, GPG3PUD);
44     writel(0x00003fc0, GPG3DRV);
45 #endif
46 #endif
47 
48 #ifdef USE_MMC3
49     /* MMC channel 3 */
50     /* 7 pins will be assigned - GPG0[0:6] = CLK, CMD, CDn, DAT[0:3] */
51     reg = readl(GPG3CON) & 0xf0000000;
52     writel(reg | 0x02222222, GPG3CON);
53     reg = readl(GPG3PUD) & 0xffffc000;
54     writel(reg | 0x00002aaa, GPG3PUD);
55     writel(0x00003fff, GPG3DRV);
56 #endif
57 }

下面來看一下smdk_s3c_hsmmc_init函式

這個函式實際是呼叫的s3c_hsmmc_initialize 這個函式 

int smdk_s3c_hsmmc_init(void)
{
    int err;

#ifdef USE_MMC0
    err = s3c_hsmmc_initialize(0);
    if(err)
        return err;
#endif

#ifdef USE_MMC1
    err = s3c_hsmmc_initialize(1);
    if(err)
        return err;
#endif    

#ifdef USE_MMC2
    err = s3c_hsmmc_initialize(2);
    if(err)
        return err;
#endif    

#ifdef USE_MMC3
    err = s3c_hsmmc_initialize(3);
    if(err)
        return err;
#endif
    return -1;
}

s3c_hsmmc_initialize 這個函式是對SoC中mmc控制器的初始化:在這個函式中主要是把我們最早定義的struct mmc中的變數以及函式指標進行了初始化;

而真正的操作暫存器的函式是

s3c_hsmmc_send_command

s3c_hsmmc_set_ios

s3c_hsmmc_init

傳送命令 傳送資料 初始化三個函式,這三個函式是最底層的直接操作GPIO、特殊功能暫存器的函式;

而這三個函式以及一些變數被封裝在struct mmc結構體中,我們作業系統對mmc裝置進行操作的時候,只到封裝以後的這個結構體中進行操作即可;

 1 static int s3c_hsmmc_initialize(int channel)
 2 {
 3     struct mmc *mmc;
 4 
 5     mmc = &mmc_channel[channel];
 6 //    printf("sdcard channel: %\n", channel);
 7     sprintf(mmc->name, "S3C_HSMMC%d", channel);
 8     mmc->priv = &mmc_host[channel];
 9     mmc->send_cmd = s3c_hsmmc_send_command;
10     mmc->set_ios = s3c_hsmmc_set_ios;
11     mmc->init = s3c_hsmmc_init;
12 //yan
13     mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
14     mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
15 #if defined(USE_MMC0_8BIT) || defined(USE_MMC2_8BIT)
16     mmc->host_caps |= MMC_MODE_8BIT;
17 #endif
18 
19     mmc->f_min = 400000;
20 //    mmc->f_max = 26000000;//52000000;
21     mmc->f_max = 52000000;
22 
23     mmc_host[channel].clock = 0;
24 
25     switch(channel) {
26     case 0:
27         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_0_BASE;
28         break;
29     case 1:
30         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_1_BASE;
31         break;
32     case 2:
33         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_2_BASE;
34         break;
35 #ifdef USE_MMC3
36     case 3:
37         mmc_host[channel].ioaddr = (void *)ELFIN_HSMMC_3_BASE;
38         break;
39 #endif
40     default:
41         printk("mmc err: not supported channel %d\n", channel);
42     }
43     
44     return mmc_register(mmc);

最後我們看一下mmc_init這個函式 這個程式碼中是呼叫了struct mmc 中的函式進行了一些時序操作

 1 int mmc_init(struct mmc *host)
 2 {
 3     int err;
 4 
 5     err = host->init(host);
 6 
 7     if (err)
 8         return err;
 9 
10     /* Reset the Card */
11     err = mmc_go_idle(host);
12 
13     if (err)
14         return err;
15 
16     /* Test for SD version 2 */
17     err = mmc_send_if_cond(host);
18 
19     /* Now try to get the SD card's operating condition */
20     err = mmc_send_app_op_cond(host);
21 
22     /* If the command timed out, we check for an MMC card */
23     if (err == TIMEOUT) {
24         err = mmc_send_op_cond(host);
25 
26         if (err)
27             return UNUSABLE_ERR;
28     } else
29         if (err)
30             return UNUSABLE_ERR;
31 
32     return mmc_startup(host);
33 }

相關推薦

UBOOT——MMC驅動分析

1:MMC驅動初始化是在start_armboot函式中 #if defined(CONFIG_X210) #if defined(CONFIG_GENERIC_MMC) puts ("SD/MMC: "); ///* //lqm masked mm

uboot原始碼——mmc驅動分析

一、uboot與linux驅動 1、uboot是裸機程式 狹義的驅動的概念:作業系統中用來具體操控硬體的那部分程式碼叫驅動。裸機中沒有驅動的概念,因為沒有作業系統。裸機程式是直接操控硬體的,而作業

Linux SD/MMC/SDIO驅動分析

一、SD/MMC/SDIO概念區分 SD(SecureDigital)與 MMC(MultimediaCard) SD 是一種 flash memory card 的標準,也就是一般常見的 SD 記憶卡,而 MMC 則是較早的一種記憶卡標準,目前已經被 SD 標準所取代。

19.Linux-USB總線驅動分析

kmalloc 開發 硬件 ctrl 地址 allow end 處理 interface 如下圖所示,以windows為例,我們插上一個沒有USB設備驅動的USB,就會提示你安裝驅動程序 為什麽一插上就有會提示信息? 是因為windows自帶了USB總線驅動程序

Kernel的IIC驅動分析

loss amp 支持 ice from see ots eno ado 涉及到的文件: drivers/i2c/i2c-core.c drivers/i2c/i2c-dev.c drivers/i2c/busses/i2c-imx.c 等等 在下面分析的代碼中,不想關

linux音頻alsa-uda134x驅動分析之二(時鐘)

lin pen play 個數 inter and 文本 ted word Audio Clocking音頻時鐘==============This text describes the audio clocking terms in ASoC and digital au

Linux 8250驅動分析

com for 目前 lin .html www. http ibm mat 1. 介紹 8250是IBM PC及兼容機使用的一種串口芯片; 16550是一種帶先進先出(FIFO)功能的8250系列串口芯片; 16550A則是16550的升級版本, 修復了FIFO相關BUG

S3C2440 linux LCD驅動分析

環境: 硬體平臺 TQ2440            東華3.5 inch  TFT LCD       

ehci及其伴隨ohci主機控制器驅動分析

1. 正常插入 插上U盤產生中斷呼叫usb_hcd_irq: usb_hcd_irq ehci_irq usb_hcd_resume_root_hub queue_work(pm_wq, &hcd->wakeup_work); //hcd.

ThoughtSpot宣佈推出面向企業的新型語音驅動分析工具SearchIQ

即將到來的頻譜授權中規定的授權條件可能阻礙對消費者和企業做出的5G承諾   倫敦--(美國商業資訊)--GSMA今日對德國政府推出整個3.4至3.8 GHz頻段(C頻段)的決定表示歡迎,該決定對全球5G業務的未來發展至關重要。及時為5G提供這一關鍵頻段內的所有頻譜,顯示出德國對躋身歐洲

camera驅動分析

1. 核心的 camera 控制器驅動 和 sensor 驅動是基於 v4l2 驅動架構編寫的,應用程式可以使用 cimutils 進行測試   CIM 控制器驅動,基於 V4L2 架構,並採用 videobuf2。便於上層開發 drivers/media/platform

uboot主Makefile分析5

1、連結指令碼(config.mk  142-149行) (1)如果定義了CONFIG_U_BOOT巨集,則連結指令碼叫u-boot-nand.lds,如果未定義這個巨集則連結指令碼叫u-boot.lds。 (2)從字面分析,即可知:CONFIG_NAND_U_BOOT是在Nand

uboot主Makefile分析4

1、$(TOPDIR)/config.mk(185行) 2、編譯工具的定義(config.mk 94-107行) 3、包含開發板配置專案(config.mk,112行) (1)autoconfig.mk檔案不是原始碼提供,是配置的過程生成的。 (2)這個檔案的作用就是用來指導uboo

uboot主Makefile分析3

1、 (1)OBJREE:編譯出的.o檔案存放的目錄的根目錄。在預設編譯下,OBJTREE等於當前目錄;在O=xx編譯下,OBJTREE就等於我們設定的那個輸出目錄. (2)SRCTREE:原始碼目錄,其實就是原始碼的根目錄,也就是當前目錄。 SRCTREE    

uboot主Makefile分析1

1、uboot_versionq確定(Makefile的24-29) (1)uboot的版本號分為3個 VERSION:主版本號 PATCHLEVEL:次版本號 SUBLEVEL:再次版本號 EXTRAVERSION:另外附加的版本資訊 這4個用.分隔開構成了最終的版本號

Linux核心啟動過程分析(十)-----RTC驅動分析

參考https://blog.csdn.net/xuao20060793/article/details/46433263這篇博文 RTC驅動分析: Class.c (drivers\rtc):subsys_initcall(rtc_init); static int __init

基於OK6410開發板Uboot原始碼簡單分析

2018-04-07 OK6410開發板是基於三星S3C6410晶片設計的一款開發板,資源比較豐富,可是想要使用這些資源就需要編寫相應的啟動載入程式,即BootLoader。當然,想要自己憑空寫出BootLoader那簡直就是天方夜譚,所以我們需要參考行業中現有的BootLoader,在其

Loongson 2K1000B IRQ驅動分析

前言 龍芯2K1000B SoC目前主要用在2K PC樣機和龍芯派上。龍芯派2代日前已經發布,將PCIE等介面引出,採用了固態硬碟作為主儲存,比先前SD卡或者USB啟動速度和穩定性均有所提高,只是暫時還不知道採用的什麼核心版本。 本文簡單分析一下龍芯派的IRQ驅

高通Camera驅動分析【轉】

1、Sensor slave配置 結構體msm_camera_sensor_slave_info定義在media/msm_cam_sensor.h中: struct msm_camera_sensor_slave_info { char sensor_name[32];

Linux--核心---I2C匯流排驅動分析 以linux3.10.0 RK3288為例

Linux 3.10.0 iic匯流排註冊過程 I2C匯流排驅動包括I2C介面卡驅動載入與解除安裝以及I2C匯流排通訊方法 I2C核心提供了i2c_adapter的增加和刪除函式、i2c_driver的增加和刪除函式、i2c_client的依附和脫離函式 以及i2c傳輸、傳送