mt6577驱动开发 笔记版
3 Preloader & Uboot
3.1 Preloader
3.1.1Preloader结构
Preloader的主题结构在文件:“alps\mediatek\platform\mt6577\preloader\src\core\main.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));
…
}
3.1.2 PLL与Clock
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:
“alps\mediatek\custom\out\mt6577\uboot\inc\configs\ubconfigs.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\n", 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\n", 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\n", 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(…)”注册自己的中断函数。
比如“alps\mediatek\custom\common\kernel\touchpanel\ft5206\ft5206_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中断触发。在“alps\mediatek\platform\mt6577\kernel\core\mt6577_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!!\n");
}
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
mediatek\source\kernel\drivers\video
static const DISP_DRIVER DSI_DISP_DRV
const LCM_DRIVER *disp_drv_get_lcm_driver(const char *lcm_name)
15.2 BL
mediatek\source\kernel\drivers\led\leds.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!\n");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_div);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail!\n");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_frequency);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail!\n");
}
rc = device_create_file(g_leds_data[i]->cdev.dev, &dev_attr_pwm_register);
if(rc)
{
LEDS_DEBUG("[LED]device_create_file duty fail!\n");
}
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
alps\mediatek\custom\common\kernel\touchpanel\ft5206
alps\mediatek\custom\common\kernel\touchpanel\src
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
mediatek\platform\mt6577\kernel\core
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\n");
retval = platform_device_register(&mt_device_usb);
if (retval != 0){
printk("mt_device_usb register fail\n");
return retval;
}
#endif
…
}
mediatek\source\kernel\drivers\usb20
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
alps\mediatek\platform\mt6577\kernel\core\Mt6577_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
alps\mediatek\platform\mt6577\kernel\drivers\i2c\I2c.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
alps\mediatek\platform\mt6577\kernel\drivers\power\pmic_mt6329.c
i2c_register_board_info 指出mt6329使用2通道
15.9 emmc & sd
C:\senix\rd\mtk\6577\source-code\src\alps\mediatek\platform\mt6577\kernel\core\ 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\rd\mtk\6577\source-code\src\alps\mediatek\platform\mt6577\kernel\drivers\mmc-host\sd.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
mt6577驱动开发 笔记版的更多相关文章
- 嵌入式linux驱动开发 笔记
@ 目录 首个驱动hellodrv 1.编写源码 2.编译模块 3.加载驱动 首个驱动hellodrv 3.如果下载不到,就自己编写,并编译驱动. 1.编写源码 2.编译模块 1.先写makefile ...
- 精通linux设备驱动开发 笔记
3.2.7 错误处理 #include <linux/err.h> char * collect_data(char *userbuffer) { char *buffer; /* ...
- Windows驱动开发工具 WDK 学习笔记(1)
目标:能够把电脑当作一个集成有高性能处理器的开发板用起来,当然,还自带了一个高级的操作系统Windows(必须的).总之,就是在一个带了操作系统的高性能开发板上的驱动程序开发. 性质:纯属业余爱好 1 ...
- Android驱动开发5-8章读书笔记
Android驱动开发读书笔记 第五章 S5PV210是一款32位处理器,具有 ...
- 第一章 Andorid系统移植与驱动开发概述 - 读书笔记
Android驱动月考1 第一章 Andorid系统移植与驱动开发概述 - 读书笔记 1.Android系统的架构: (1)Linux内核,Android是基于Linux内核的操作系统,并且开源,所以 ...
- 驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址
驱动开发学习笔记. 0.07 Uboot链接地址 加载地址 和 链接脚本地址 最近重新看了乾龙_Heron的<ARM 上电启动及 Uboot 代码分析>(下简称<代码分析>) ...
- 驱动开发学习笔记. 0.06 嵌入式linux视频开发之预备知识
驱动开发读书笔记. 0.06 嵌入式linux视频开发之预备知识 由于毕业设计选择了嵌入式linux视频开发相关的项目,于是找了相关的资料,下面是一下预备知识 UVC : UVC,全称为:USB v ...
- 驱动开发学习笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇
驱动开发读书笔记. 0.05 linux 2.6 platform device register 平台设备注册 2/2 共2篇 下面这段摘自 linux源码里面的文档 : 内核版本2.6.22Doc ...
- 驱动开发学习笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇
驱动开发读书笔记. 0.04 linux 2.6 platform device register 平台设备注册 1/2 共2篇下面这段摘自 linux源码里面的文档 : Documentatio ...
随机推荐
- 开源框架Volley的使用《二》[NetWorkImageView&&LruCache&ImageLoader]
转载本专栏每一篇博客请注明转载出处地址,尊重原创.此博客转载链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/5278849 ...
- Apache DbUtils 探秘
听说Apache的DbUtils很好用,而且是对jdbc的简单的封装,所以可以和jdbc一起混搭,多以今天就来尝试一下,关于DbUtils 是如何使用的. 准备 数据库: MySQL 依赖: mysq ...
- Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 下篇
Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 上篇blog讲述了加权轮询算法的原理.以及负载均衡模块中使用的数据结构,接着我们来看看加权轮询算法的具 ...
- struts1.x mvc简单例程
因为项目需要,需要使用struts1.x .因此学习下struts框架. 例程从struts 实现MVC框架入手,完成一次request请求. 一.前台 两个jsp文件 index.jsp: 只有一个 ...
- tomcat如何路由映射网址
对于web容器来说,根据请求客户端路径路由到对应的资源属于其核心功能,假设用户在自己电脑上使用浏览器输入网址http://www.test.com/test/index.jsp,报文通过互联网网络到达 ...
- 取KindEditor中的textarea的值区不到的解决方案,固定kindEditor的高度
可以通过下面的方式取到textarea的值 var content = $(document.getElementsByTagName('iframe')[0].contentWindow.do ...
- postman使用—chrome版
如果大家不知道怎么安装,请下载个FQ软件(蓝灯,shadowsocks)都是可以的,安装完成之后,你可以在chrome看到posman的插件程序. 使用说明: 安装完成之后,使用chrome://ap ...
- TCP的定时器系列 — 超时重传定时器
主要内容:TCP定时器概述,超时重传定时器.ER延迟定时器.PTO定时器的实现. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd Q:一条TCP连接会使用 ...
- Linux IPC实践(1) -- 概述
进程的同步与互斥 进程同步: 多个进程需要相互配合共同完成一项任务. 进程互斥: 由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥;系统中某些 ...
- HTML入门笔记
HTML简介 HTML是做网页最基本的技术 1_由标签组件 2_在任何操作系统平台,只要有浏览器,都有执行HTML 3_浏览器中有HTML解析器 4_编辑HTML可以使用任何文本编辑工具,如记事本,建 ...