3.1 Preloader
3.1.1Preloader结构
Preloader的主题结构在文件:“alpsmediatekplatformmt6577preloadersrccoremain.c”中。
void main(void)
{
//时钟、uart、mcp等初始化
bldr_pre_process();
…
bldr_handshake(&handler);
…
//这里加载DSP 3G AP的ROM。
…
#if CFG_LOAD_UBOOT
addr = CFG_UBOOT_MEMADDR;
//加载uboot
if (bldr_load_part(PART_UBOOT, bootdev, &addr) != 0)
goto error;
#endif
…
//跳转到uboot
bldr_jump(addr, BOOT_ARGUMENT_ADDR, sizeof(boot_arg_t));
…
}
PLL介绍在datasheet 1190
Pll.c中“void mt6577_pll_init(void)”
似乎PLL主要是在preloader里打开的。
//设置的PLL
void mt6577_pll_init(void)
{
}
//根据MCP的型号设置DDR相关时钟
int mt6577_pll_init2 (void)
{
if (mt6577_get_dram_type() == 2)
{
…
}
else if (mt6577_get_dram_type() == 3)
{
…
}
}
3.1.3 DDR的初始化
EMI_SETTINGS emi_settings[]里面定义了KMNJS000ZM_B205 H9TP32A4GDMCPR KMSJS000KM_B308等类型的MCP的配置参数。
在“void mt6577_set_emi (void)”里面会根据“emi_settings[]”的配置初始化MCP控制器。
3.1.4 镜像布局与加载
镜像布局参数被存放在文件:
mediatek/custom/out/mt6577preloader/cust_part.c里
static part_t platform_parts[PART_MAX_COUNT];里面记录每个镜像的长度。
在mediatek/platform/mt6577/preloader/src/core/part.c里
函数int part_init(void)里,依次累加前面所有镜像,算出当前镜像的起始位置。
3.1.5 EMMC 驱动
#define MMC_HOST_ID 0
u32 mmc_init_device(void)
{…
//emmc 零通道
ret = mmc_init(MMC_HOST_ID);
…
}
//分别初始化host和card
int mmc_init(int id)
{
…
host = &sd_host[id];
card = &sd_card[id];
err = mmc_init_host(host, id);
if (err == MMC_ERR_NONE)
err = mmc_init_card(host, card);
…
}
//host初始化
int mmc_init_host(struct mmc_host *host, int id)
{
memset(host, 0, sizeof(struct mmc_host));
return msdc_init(host, id);
}
/*
#define MSDC0_BASE (IO_PHYS + 0x01220000)
#define MSDC1_BASE (IO_PHYS + 0x01230000)
#define MSDC2_BASE (IO_PHYS + 0x01250000)
#define MSDC3_BASE (IO_PHYS + 0x01240000)
#define IO_PHYS 0xC0000000
对于通道0,基地址在MSDC0_BASE即为0xC1220000。其余通道基地址在0xC1230000 0xC1240000 0xC1250000,但是datasheet里只有0通道0xC1220000的信息。
*/
int msdc_init(struct mmc_host *host, int id)
{
u32 baddr[] = {MSDC0_BASE, MSDC1_BASE, MSDC2_BASE, MSDC3_BASE};
//基地址选择0通道
u32 base = baddr[id];
//0通道
host->id = id;
//基地址
host->base = base;
host->f_max = MSDC_MAX_SCLK;
…
//以下所有对0通道的寄存器操作都是基于这基地址“base”进行的
}
3.3 uboot
Uboot代码:
Generic部分:
Uboot的generic的部分位于“bootable/bootloader/uboot/”
Mt6577相关部分相关位于:
mediatek/platform/mt6577/uboot/
mediatek/custom/out/mt6577/uboot/
uboot的config:
“alpsmediatekcustomoutmt6577ubootincconfigsubconfigs.h”
3.3.1 uboot初始化流程
Uboot初始化主体位于“bootable/bootloader/uboot/arch/arm/lib/board.c”
void start_armboot (void)
{
…
//执行初始化例程数组
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
{
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
…
//执行平台相关misc初始化
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r ();
#endif
}
在“bootable/bootloader/uboot/arch/arm/lib/board.c”定义了初始化例程指针数组,其中的各项例程不同的板卡有自己不同的实现:
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
dram_init, /* configure available RAM banks */ /* change the original init order */
board_init, /* basic board dependent setup */
interrupt_init,/* set up exceptions */
env_init, /* initialize environment */
init_baudrate,/* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f,/* stage 1 init of console */
display_banner,/* say that we are here */
…
display_dram_config,
NULL,
};
Mt6577的初始化例程的实现位于“mediatek/platform/mt6577/uboot/mt6577_board.c”:
int board_init (void)
{…
mtk_serial_init();
…
mt6577_pinmux_init();s
…
pmic6329_init();
}
3.3.2 镜像布局与分区
Uboot在“int misc_init_r (…)”里对镜像分区初始化
int misc_init_r (void)
{…
mt6577_part_init(BLK_NUM(16 * GB));
…
}
/**********************************************************************/
在“mediatek/custom/out/mt6577/uboot/partition.h”里对分区表定义如下:
#include <common.h>
/*该文件可能就是:
“mediatek/custom/out/mt6577/uboot/inc/mt65xx_partition.h”
*/
#include "mt65xx_partition.h"
part_t partition_layout[] = {
{PART_PRELOADER, PART_BLKS_PRELOADER, PART_FLAG_NONE,0},
{PART_DSP_DL, PART_BLKS_DSP_DL, 0, PART_FLAG_NONE},
…
};
3.3.3 gpio初始化
DCT工具产生的“cust_gpio_boot.h”被如下文件:
mediatek/platform/mt6577/uboot/mt6577_gpio_init.c
默认设置的定义:
u16 gpio_init_mode_data[];
u16 gpio_init_dir_data[];
u16 gpio_init_pullen_data[];
…
设置默认设置
void mt_gpio_set_default(void)
4 Kernel
内核源码
标准内核:
Alps/kernel
Mtk部分内核
? Alps/mediatek/source/kernel/
? Alps/mediatek/platform/mt6577/kernel
? Alps/mediatek/custom/*/kernel下面也有,如
Alps/mediatek/custom/common/kernel
Alps/mediatek/custom/mt6577/kernel
4.1 ARCH初始化
4.1.1 Board支持
在“alps/mediatek/platform/mt6577/kernel/core/core.c”定义
MACHINE_START(MT6577, "MT6577")
.boot_params = PHYS_OFFSET + 0x00000100,
.map_io = mt6577_map_io,
.init_irq = mt_init_irq,
.timer = &mt6577_timer,
.init_machine = mt6577_init,
.fixup = mt6577_fixup
MACHINE_END
在“alps/mediatek/platform/mt6577/kernel/core/mt6577_devs.c”注册device
__init int mt6577_board_init(void)
{
…
retval = platform_device_register(&mt_hid_dev);
retval = platform_device_register(&mt_device_i2c[i]);
retval = platform_device_register(&AudDrv_device);
retval = platform_device_register(&mt6577_device_fb);
retval = platform_device_register(&mtk_hdmi_dev);
retval = platform_device_register(&mt6577_TVOUT_dev);
…
}
在“alps/kernel/mediatek/Makefile”里引用“../../mediatek/build/kernel/Makefile”,该文件即为:“alps/mediatek/build/kernel/Makefile”里面定义了相关的mt6577的内核文件:
machine-y := $(call lc,$(MTK_PLATFORM))
ifeq ($(strip $(KBUILD_OUTPUT_SUPPORT)),yes)
MACHINE := mediatek/platform/$(call lc,$(MTK_PLATFORM))/kernel/core/
machdirs := mediatek/platform/$(call lc,$(MTK_PLATFORM))/kernel/core/
else
MACHINE := $(MTK_PATH_PLATFORM)/core/
machdirs := $(MTK_PATH_PLATFORM)/core/
endif
platdirs :=
ifeq ($(strip $(KBUILD_OUTPUT_SUPPORT)),yes)
drivers-y += mediatek/source/kernel/
drivers-y += mediatek/custom/out/$(FULL_PROJECT)/kernel/
drivers-y += mediatek/platform/$(call lc,$(MTK_PLATFORM))/kernel/drivers/
else
drivers-y += $(MTK_PATH_PLATFORM)/drivers/
drivers-y += $(MTK_PATH_SOURCE)/
drivers-y += $(MTK_PATH_CUSTOM)/
endif
4.1.2 PLL与Clock
mt6577_clock_manager.c中“static void mt6577_clock_init(void)”“static void mt6577_pll_init(void)”
mt6577的clock定义如下
enum mt65xx_clock_id {
/* PERI_GLOBALCON_PDN0 */
MT65XX_PDN_PERI_NFI = 0,
…
/* PERI_GLOBALCON_PDN1 */
MT65XX_PDN_PERI_SEJ = 32,
…
/* MMSYS1 Clock Gating #0 */
MT65XX_PDN_MM_VBUF = 64,
…
/* MMSYS1 Clock Gating #1 */
MT65XX_PDN_MM_VRZ1 = 96,
…
/*MMSYS1 Clock Gating #2 */
MT65XX_PDN_MM_SCAM = 128,
…
MT65XX_CLOCK_AUDIO_PDN, /* 32*6 = 192*/
MT65XX_AUDIO_PDN_END = MT65XX_PDN_AUDIO_I2S,
MT65XX_CLOCK_COUNT,
};
按照32,分组,enbale某个clock时,首先找到分组,然后找到组内偏移,针对某个组进行操作。中间根据clock组编号区分出 AP AP1 MM1 MM2等不同始终组,进行特殊操作。
不同的驱动在自己初始化函数里enable自己需要clock id—实际上enable对应的clock组。
int enable_clock(enum mt65xx_clock_id id, char *mod_name)
{
unsigned long flags;
int ret = 0;
int category = id / CLK_REG_WIDTH;
int offset = id % CLK_REG_WIDTH;
if (CATEGORY_AP1(category)) {
…
}
…
if (CATEGORY_MM(category)) {
…
}
if (CATEGORY_AUD(category)) {
…
}
ret = enable_clock_internal(category, mask);
5 CpuFreq
5.1 初始化
在“static int mtk_cpufreq_init(…)”里根据处理器的版本选择调频表:
static struct mtk_cpu_freq_info mt6575_freqs_e1[] = {
OP(DVFS_F2_MT6575_E1),
OP(DVFS_F1_MT6575_E1),
};
/***************************
* MT6575 E2 DVFS Table
****************************/
static struct mtk_cpu_freq_info mt6575_freqs_e2[] = {
OP(DVFS_F4_MT6575_E2),
…
};
/***************************
* MT6577 E1 DVFS Table
****************************/
static struct mtk_cpu_freq_info mt6577_freqs_e1[] = {
OP(DVFS_F6_MT6577_E1),
…
OP(DVFS_F1_MT6577_E1),
};
/***************************
* MT6577 E1 TM DVFS Table
****************************/
static struct mtk_cpu_freq_info mt6577_freqs_e1_tm[] = {
OP(DVFS_F6_MT6577_E1_TM),
…
OP(DVFS_F1_MT6577_E1_TM),
};
调频操作在“static int mtk_cpufreq_target()”里完成。
5.2 基本数据结构
调频例程
static struct cpufreq_driver mtk_cpufreq_driver = {
.verify = mtk_cpufreq_verify,
.target = mtk_cpufreq_target,
.init = mtk_cpufreq_init,
.get = mtk_cpufreq_get,
.name = "mtk-cpufreq",
};
5.7 调频
/**********************************
* cpufreq target callback function
***********************************/
/*************************************************
* [note]
* 1. handle frequency change request
* 2. call mtk_cpufreq_set to set target frequency
**************************************************/
static int mtk_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
{
…
/******************************
* look up the target frequency
*******************************/
if (cpufreq_frequency_table_target(policy, mtk_cpu_freqs_table, target_freq, relation, &idx))
return -EINVAL;
//idx是目标调频点索引值
if (get_chip_ver() >= CHIP_6577_E1)
{…
}
else if (get_chip_ver() >= CHIP_6575_E2)
{
next = &mt6575_freqs_e2[idx];
}
…
// next指向目标调频点
// freqs.old是当前频点,freqs.new是目标频点
freqs.old = policy->cur;
freqs.new = next->cpufreq_mhz;
freqs.cpu = policy->cpu;
#ifndef MTK_DVFS_RANDOM_TEST
if (mtk_cpufreq_keep_max_freq(freqs.old, freqs.new))
{
if ((DRV_Reg32(HW_RESV) & (0x1 << 23)) && ((DRV_Reg32(HW_RESV) & (0x1 << 20)) == 0))
freqs.new = DVFS_F1_TM;
else
freqs.new = DVFS_F1;
}
if (freqs.new > g_limited_freq)
{
dprintk("CPU frequency has been limited to %d Mhz, request %d Mhz will be limited ", g_limited_freq / 1000, freqs.new / 1000);
freqs.new = g_limited_freq;
}
if (freqs.new < g_limited_min_freq)
{
dprintk("cannot switch CPU frequency to %d Mhz due to voltage limitation ", g_limited_min_freq / 1000);
freqs.new = g_limited_min_freq;
}
#endif
/************************************************
* target frequency == existing frequency, skip it
*************************************************/
if (freqs.old == freqs.new)
{
dprintk("CPU frequency from %d MHz to %d MHz (skipped) due to same frequency ", freqs.old / 1000, freqs.new / 1000);
return 0;
}
/*调频前对所有ONLINE CPU发出通知*/
for_each_online_cpu(cpu)
{
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
}
spin_lock_irqsave(&mtk_cpufreq_lock, flags);
/*********************************************
* update current frequency due to last change
**********************************************/
freqs.old = g_cur_freq;
/******************************
* set to the target freeuency
*******************************/
//真正的调频操作
mtk_cpufreq_set(freqs.old, freqs.new);
spin_unlock_irqrestore(&mtk_cpufreq_lock, flags);
/*调频后对所有ONLINE CPU发出通知*/
for_each_online_cpu(cpu)
{
freqs.cpu = cpu;
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
}
return 0;
}
/*****************************************
* frequency ramp up and ramp down handler
******************************************/
/***********************************************************
* [note]
* 1. frequency ramp up need to wait voltage settle
* 2. frequency ramp down do not need to wait voltage settle
************************************************************/
static void mtk_cpufreq_set(unsigned int freq_old, unsigned int freq_new)
{
if (freq_new == DVFS_F1 || freq_new == DVFS_F1_TM) /* set ARMPLL divider to 1/1 */
{
…
}
else if (freq_new == DVFS_F2 || freq_new == DVFS_F2_TM) /* set ARMPLL divider to 5/6 */
{
if (freq_new > freq_old)
{ //升频,先调压再调频
//调压
#ifdef MTK_BUCK_ADJUST
DRV_WriteReg32(SC_AP_DVFS_CON, ((DRV_Reg32(SC_AP_DVFS_CON) & 0xFFFFFFFC) | 0x03));
mb();
udelay(PMIC_SETTLE_TIME);
#endif
g_cur_freq = freq_new;
//调频
DRV_WriteReg32(TOP_CKDIV1, 0x19);
}
else
{ //降频,先调频再调压
//调频
g_cur_freq = freq_new;
DRV_WriteReg32(TOP_CKDIV1, 0x19);
mb();
//调压
#ifdef MTK_BUCK_ADJUST
DRV_WriteReg32(SC_AP_DVFS_CON, ((DRV_Reg32(SC_AP_DVFS_CON) & 0xFFFFFFFC) | 0x03));
#endif
}
}
else if (freq_new == DVFS_F3 || freq_new == DVFS_F3_TM) /* set ARMPLL divider to 3/4 */
{
}
else if (freq_new == DVFS_F4 || freq_new == DVFS_F4_TM) /* set ARMPLL divider to 2/3 */
{
}
else if (freq_new == DVFS_F5 || freq_new == DVFS_F5_TM) /* set ARMPLL divider to 1/2 */
{
}
else if (freq_new == DVFS_F6 || freq_new == DVFS_F6_TM) /* set ARMPLL divider to 1/4 */
{
}
else if (freq_new == DVFS_F7 || freq_new == DVFS_F7_TM) /* set ARMPLL divider to 1/6 */
{
}
}
6 IRQ
6.1 中断体系
根据arm gic规范,
0-15 SGI
16-31 PPP
32以上 SPI
6.3 外部中断
typedef struct
{
void (*eint_func[EINT_MAX_CHANNEL])(void);
unsigned int eint_auto_umask[EINT_MAX_CHANNEL];
} eint_func;
通过“void mt65xx_eint_registration(…)”注册自己的中断函数。
比如“alpsmediatekcustomcommonkernel ouchpanelft5206ft5206_driver.c”通过该函数注册自己的中断处理函数:
mt65xx_eint_registration(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_EN, CUST_EINT_POLARITY_HIGH, tpd_eint_interrupt_handler, 1);
外部中断的入口是“static irqreturn_t mt65xx_eint_isr(int irq, void *dev_id)”,该函数会检查“eint_func”数组里的处理函数。而整个外部中断入口是由EINT_IRQ中断触发。在“alpsmediatekplatformmt6577kernelcoremt6577_eint.c”将EINT_IRQ中断挂入6577的中断体系。
if (request_irq(EINT_IRQ, mt65xx_eint_isr, IRQF_TRIGGER_HIGH, "EINT", NULL)) {
printk(KERN_ERR "EINT IRQ LINE NOT AVAILABLE!! ");
}
6.4 wakeup
static u16 sc_wake_irq[NUM_WAKE_SRC] = {
[2] = MT6577_KP_IRQ_ID,
[3] = MT6577_MSDC1_IRQ_ID,
[5] = MT6577_EINT_IRQ_ID,
[6] = MT6577_RTC_IRQ_ID,
[7] = MT6577_AP_CCIF_IRQ_ID,
[8] = MT6577_ACCDET_IRQ_ID,
};
15 Driver
15.1 LCM
修改lps/mediatek/config/common/ProjectConfig.mk”里的“CUSTOM_KERNEL_LCM”和 “CUSTOM_UBOOT_LCM”选项将影响到文件“alps/mediatek/config/out/mt6577/ProjectConfig.mk”
将上述两项CUSTOM_KERNEL_LCM=hx8369_6575 CUSTOM_UBOOT_LCM=hx8369_6575
导致
alps/mediatek/custom/common/kernel/lcm/hx8369_6575/hx8369_6575.c拷到如下两个目录
alps/mediatek/custom/out/mt6577/kernel/lcm
alps/mediatek/custom/out/mt6577/uboot/lcm
mediateksourcekerneldriversvideo
static const DISP_DRIVER DSI_DISP_DRV
const LCM_DRIVER *disp_drv_get_lcm_driver(const char *lcm_name)
15.2 BL
mediateksourcekerneldriversledleds.c
{
if(strcmp(g_leds_data[i]->cdev.name,"lcd-backlight") == 0)
{
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_duty);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail! ");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_div);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail! ");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_frequency);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail! ");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_pwm_register);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail! ");
}
bl_setting = &g_leds_data[i]->cust;
}
}
static DEVICE_ATTR(duty, 0664, show_duty, store_duty);
g_leds_data
[ 40.450409] (0)[313:ScreenOffThread][LED]Set Backlight directly 102 at time 4294941336
[ 40.451398] (0)[313:ScreenOffThread]mt65xx_leds_set_cust: set brightness, name:lcd-backlight, mode:3, level:102
[ 40.452744] (0)[313:ScreenOffThread]brightness_set_pmic1[LED]PMIC#3:102
[ 40.454159] (0)[313:ScreenOffThread]brightness_set_pmic3 2
brightness_set_pmic
mt65xx_leds_brightness_set
led_brightness_set
15.3 TP
alpsmediatekcustomcommonkernel ouchpanelft5206
alpsmediatekcustomcommonkernel ouchpanelsrc
15.5 Musb
15.5.1 配置
尽管在
mediatek/config/mt6577/autoconfig/kconfig/platform
CONFIG_USB_MTK_HDRC_HCD is not set
CONFIG_USB_MTK_OTG is not set
但是在
mediatek/config/mt6577/autoconfig/kconfig/project
CONFIG_USB_MTK_HDRC_HCD=y
CONFIG_USB_MTK_OTG=y
15.5.2 Platform device & driver
mediatekplatformmt6577kernelcore
struct platform_device mt_device_usb = {
.name = "mt_usb",
.id = -1,
.dev = {
//.platform_data = &usb_data_mt65xx,
.dma_mask = &usb_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
//.release=musbfsh_hcd_release,
},
};
__init int mt6577_board_init(void)
{
…
#if defined(CONFIG_USB_MTK_HDRC)
printk("mt_device_usb register ");
retval = platform_device_register(&mt_device_usb);
if (retval != 0){
printk("mt_device_usb register fail ");
return retval;
}
#endif
…
}
mediateksourcekerneldriversusb20
static struct platform_driver musb_driver = {
.driver = {
.name = (char *)musb_driver_name,
.owner = THIS_MODULE,
},
.remove = __exit_p(musb_remove),
.shutdown = musb_shutdown,
.probe = musb_probe,
};
data_array[0]=0x00103902;
data_array[1]=0x032000B2;
data_array[2]=0xFF007003;
data_array[3]=0x00000000;
data_array[4]=0x01000303;
dsi_set_cmdq(&data_array, 5, 1);
data_array[0] 为packet head 定义为:第一个字节为 WC1,第二个字节WC0,第三个字节DT (命令类型)第四个字节为控制类型。
data_array[1],data_array[2],data_array[3],data_array[4],为初始化的相应数据。
15.6 GPIO
GPIO初始化在uboot里完成
GPIO在内核的定义:
cust_gpio_usage.h
GPIO在内核的设置
mt_set_gpio_mode
15.7 IIC
15.7.1 adapter device
alpsmediatekplatformmt6577kernelcoreMt6577_devs.c
static struct platform_device mt_device_i2c[] = {
{
.name = "mt-i2c",
.id = 0,
.num_resources = ARRAY_SIZE(mt_resource_i2c1),
.resource = mt_resource_i2c1,
},
…
{
.name = "mt-i2c",
.id = 2,
.num_resources = ARRAY_SIZE(mt_resource_i2c3),
.resource = mt_resource_i2c3,
},
};
15.7.2 adapter driver
alpsmediatekplatformmt6577kerneldriversi2cI2c.c
static struct platform_driver mt_i2c_driver = {
.probe = mt_i2c_probe,
.remove = mt_i2c_remove,
#ifdef CONFIG_PM
.suspend = mt_i2c_suspend,
.resume = mt_i2c_resume,
#endif
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
15.7.3 匹配IIC通道
i2c_register_board_info
15.8 PMIC MT6329
alpsmediatekplatformmt6577kerneldriverspowerpmic_mt6329.c
i2c_register_board_info 指出mt6329使用2通道
15.9 emmc & sd
C:senix dmtk6577source-codesrcalpsmediatekplatformmt6577kernelcore mt6577_devs.c
static struct platform_device mt6577_device_sd[] =
{
#if defined(CFG_DEV_MSDC0)
{
.name = "mtk-sd",
.id = 0,
.num_resources = ARRAY_SIZE(mt6577_resource_sd0),
.resource = mt6577_resource_sd0,
.dev = {
.platform_data = &msdc0_hw,
},
},
#endif
#if defined(CFG_DEV_MSDC1)
{
.name = "mtk-sd",
.id = 1,
.num_resources = ARRAY_SIZE(mt6577_resource_sd1),
.resource = mt6577_resource_sd1,
.dev = {
.platform_data = &msdc1_hw,
},
},
#endif
#if defined(CFG_DEV_MSDC2)
{
.name = "mtk-sd",
.id = 2,
.num_resources = ARRAY_SIZE(mt6577_resource_sd2),
.resource = mt6577_resource_sd2,
.dev = {
.platform_data = &msdc2_hw,
},
},
#endif
#if defined(CFG_DEV_MSDC3)
{
.name = "mtk-sd",
.id = 3,
.num_resources = ARRAY_SIZE(mt6577_resource_sd3),
.resource = mt6577_resource_sd3,
.dev = {
.platform_data = &msdc3_hw,
},
},
#endif
};
驱动
c:senix dmtk6577source-codesrcalpsmediatekplatformmt6577kerneldriversmmc-hostsd.c
EMMC数据线定义
struct msdc_hw msdc0_hw = {
.clk_src = 1,
.cmd_edge = MSDC_SMPL_FALLING,
.data_edge = MSDC_SMPL_FALLING,
…
.data_pins = 8,
.data_offset = 0,
#ifdef MTK_EMMC_SUPPORT
.flags = MSDC_SYS_SUSPEND | MSDC_HIGHSPEED,
#else
.flags = MSDC_SDCARD_FLAG,
#endif
};
static struct mmc_host_ops mt_msdc_ops = {
.request = msdc_ops_request,
.set_ios = msdc_ops_set_ios,
.get_ro = msdc_ops_get_ro,
.get_cd = msdc_ops_get_cd,
.enable_sdio_irq = msdc_ops_enable_sdio_irq,
.start_signal_voltage_switch = msdc_ops_switch_volt,
};
Host
Mmc card device
Mmc card driver
mmc_rescan 扫描mmc 家里mmc设备
mmc_init_card
mmc_blk_probe
?add_disk