• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

linux eMMC驱动

武飞扬头像
JDSH0224
帮助1

目录

0.说明

1.设备树初始化

2.申请mmc主机控制器

3.配置mmc的时钟配置

4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)

5.启动硬件atmci_interrupt中断,处理mmc控制器的状态

6.配置DMA

7.设置一个超时的软定时器

8.初始化mmc插槽

9.初始化debugfs文件系统

10.提供给上层的访问数据接口

11.启动信息

12. eMMC获取CSD


0.说明

基于A5D36平台eMMC驱动分析,设备和驱动匹配之后调用atmci_probe

1.设备树初始化

atmci_of_init
  of_property_read_u32(cnp, "reg", &slot_id)
  of_get_named_gpio(cnp, "cd-gpios", 0)
  of_property_read_u32(cnp, "bus-width",&pdata->slot[slot_id].bus_width //获取总线
  of_property_read_bool(cnp, "cd-inverted")
  of_property_read_bool(cnp, "non-removable")
  of_get_named_gpio(cnp, "wp-gpios", 0)

2.申请mmc主机控制器

struct atmel_mci *host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); //申请atmel host主机控制器

3.配置mmc的时钟配置

//3.配置mmc的时钟配置
host->mck = devm_clk_get(&pdev->dev, "mci_clk"); //mci_clk在哪里定义的???
host->bus_hz = clk_get_rate(host->mck); //host->bus_hz数值是多少???

4.4.启动tasklet(下半部延时任务处理),基于状态机处理硬件中断(上半部紧急的事务)

tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
  atmci_tasklet_func
    case STATE_IDLE:  //状态空闲
      
    case STATE_SENDING_CMD: //发送命令中
      atmci_test_and_clear_pending(host, EVENT_CMD_RDY) //条件成立,执行下面的流程
      atmci_set_completed(host, EVENT_CMD_RDY); //设置完成命令 EVENT_CMD_RDY
      atmci_command_complete(host, mrq->cmd) //从 atmci_interrupt -> ATMCI_CMDRDY 中获取到的数据处理,分几种情况
        state = STATE_END_REQUEST;  //命令错误,直接结束
        state = STATE_DATA_XFER;  //数据传输
        state = STATE_WAITING_NOTBUSY;  //写空闲
        state = STATE_END_REQUEST;  //结束请求
    case STATE_DATA_XFER: //数据传输
      atmci_test_and_clear_pending(host, EVENT_XFER_COMPLETE)
      atmci_set_completed(host, EVENT_XFER_COMPLETE);
      if (host->caps.need_notbusy_for_read_ops ||(host->data->flags & MMC_DATA_WRITE))
        state = STATE_WAITING_NOTBUSY;  //
      else if (host->mrq->stop) 
        state = STATE_SENDING_STOP;
      else
        state = STATE_END_REQUEST;
    case STATE_WAITING_NOTBUSY: //非忙等待
      atmci_test_and_clear_pending(host, EVENT_NOTBUSY)
      atmci_set_completed(host, EVENT_NOTBUSY);
      if (host->mrq->stop) 
        state = STATE_SENDING_STOP;
      else
        state = STATE_END_REQUEST;
    case STATE_SENDING_STOP:  //发送停止
      atmci_test_and_clear_pending(host, EVENT_CMD_RDY)
      if (mrq->stop->error)
        state = STATE_END_REQUEST
      else
        state = STATE_WAITING_NOTBUSY;
    case STATE_END_REQUEST: //停止请求
      state = STATE_IDLE

5.启动硬件atmci_interrupt中断,处理mmc控制器的状态

request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
  atmci_interrupt   
    ATMCI_DATA_ERROR_FLAGS  //数据错误标识
      atmci_set_pending(host, EVENT_DATA_ERROR); //设置 EVENT_DATA_ERROR
      tasklet_schedule(&host->tasklet);  //任务调度
    ATMCI_TXBUFE  //数据发送为空
      atmci_pdc_complete
        atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
        tasklet_schedule(&host->tasklet);  //任务调度
    ATMCI_ENDTX   //数据结束发送  
    ATMCI_RXBUFF  //数据接收缓冲满
      atmci_pdc_complete
        sg_copy_from_buffer(host->data->sg, host->data->sg_len, host->buffer, transfer_size); //数据拷贝到host->data->sg,非常重要!!!
        atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
        tasklet_schedule(&host->tasklet);  //任务调度
    ATMCI_ENDRX   //数据结束接收
    ATMCI_BLKE    //数据块已结束
      atmci_set_pending(host, EVENT_NOTBUSY);
      tasklet_schedule(&host->tasklet);
    ATMCI_NOTBUSY //数据不忙
      atmci_set_pending(host, EVENT_NOTBUSY);
      tasklet_schedule(&host->tasklet);
    ATMCI_RXRDY   //数据接收
      atmci_read_data_pio //接收数据
        struct scatterlist  *sg = host->sg;    //以下是从寄存器提取数据到缓存
        void *buf = sg_virt(sg);
        value = atmci_readl(host, ATMCI_RDR);
        put_unaligned(value, (u32 *)(buf   offset));
        
        atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
    ATMCI_TXRDY   //数据发送
      atmci_write_data_pio  //发送数据
        struct scatterlist  *sg = host->sg;    //以下是从缓存提取数据到寄存器
        void *buf = sg_virt(sg);
        value = get_unaligned((u32 *)(buf   offset));
        atmci_writel(host, ATMCI_TDR, value); 
        
        atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
    ATMCI_CMDRDY
      atmci_set_pending(host, EVENT_CMD_RDY); //设置 EVENT_CMD_RDY
      tasklet_schedule(&host->tasklet);    //任务调度
    ATMCI_SDIOIRQA | ATMCI_SDIOIRQB
      atmci_sdio_interrupt
        mmc_signal_sdio_irq

6.配置DMA

atmci_configure_dma
  if (ret == 0) {
    host->prepare_data = &atmci_prepare_data_dma;
    host->submit_data = &atmci_submit_data_dma;
    host->stop_transfer = &atmci_stop_transfer_dma;
  } else if (host->caps.has_pdc) {
    dev_info(&pdev->dev, "using PDC\n");
    host->prepare_data = &atmci_prepare_data_pdc;
    host->submit_data = &atmci_submit_data_pdc;
    host->stop_transfer = &atmci_stop_transfer_pdc;
  } else {
    dev_info(&pdev->dev, "using PIO\n");
    host->prepare_data = &atmci_prepare_data;
    host->submit_data = &atmci_submit_data;
    host->stop_transfer = &atmci_stop_transfer;
  }

7.设置一个超时的软定时器

setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
  atmci_timeout_timer //任务超时将执行以下动作
    host->state = STATE_END_REQUEST; //停止请求,交给 atmci_tasklet_func 处理
    tasklet_schedule(&host->tasklet);  //启动调度

8.初始化mmc插槽

//8.初始化mmc插槽      
atmci_init_slot
  struct mmc_host *mmc = mmc_alloc_host(sizeof(struct atmel_mci_slot), &host->pdev->dev)  //初始化一个mmc主控制器
    dev_set_name(&host->class_dev, "mmc%d", host->index); //mmc0
    INIT_DELAYED_WORK(&host->detect, mmc_rescan);
      mmc_rescan
        for (i = 0; i < ARRAY_SIZE(freqs); i  ) //static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
          mmc_rescan_try_freq(host, max(freqs[i], host->f_min)
            sdio_reset
              mmc_io_rw_direct_host
                mmc_wait_for_cmd
                  mmc_wait_for_req
                    __mmc_start_req
                      mmc_start_request
                        host->ops->request(host, mrq) //.request  = atmci_request, //见下分析
                    mmc_wait_for_req_done
      mmc_go_idle
        //组织eMMC格式数据
        struct mmc_command cmd = {0};
        cmd.opcode = MMC_GO_IDLE_STATE;
        cmd.arg = 0;
        cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
        //mmc发送cmd
        mmc_wait_for_cmd(host, &cmd, 0) //具体流程同上
          struct mmc_request mrq = {NULL};
          cmd->retries = retries;
          mrq.cmd = cmd;
          cmd->data = NULL;
          mmc_wait_for_req(host, &mrq)
            __mmc_start_req(host, mrq);
            mmc_wait_for_req_done(host, mrq);
      mmc_send_if_cond
        struct mmc_command cmd = {0};
        cmd.opcode = SD_SEND_IF_COND;
        cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
        cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
        mmc_wait_for_cmd(host, &cmd, 0);
      mmc_attach_sdio //未使用
      mmc_attach_sd //未使用
      mmc_attach_mmc  //mmc主控制器连接mmc
        mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN) //设置mmc的总线模式
          host->ios.bus_mode = mode;
          mmc_set_ios(host);
            //调试信息输出
            pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u " "width %u timing %u\n",
            mmc_hostname(host), ios->clock, ios->bus_mode, ios->power_mode, ios->chip_select, ios->vdd, ios->bus_width, ios->timing);
            //设置io总线
            host->ops->set_ios(host, ios) //.set_ios  = atmci_set_ios
              atmci_set_ios //见下分析
        mmc_send_op_cond(host, 0, &ocr) //设置card的工作电压寄存器OCR,并且通过busy位(bit31)来判断card的上电复位过程是否完成,如果没有完成的话需要重复发送。 
          struct mmc_command cmd = {0};
          cmd.opcode = MMC_SEND_OP_COND;
          cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
          cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;      
          mmc_wait_for_cmd(host, &cmd, 0)
        mmc_attach_bus(host, &mmc_ops)
          host->bus_ops = ops;
          //以下为总线结构体定义
          static const struct mmc_bus_ops mmc_ops = {
            .remove = mmc_remove,
            .detect = mmc_detect,
            .suspend = mmc_suspend,
            .resume = mmc_resume,
            .runtime_suspend = mmc_runtime_suspend,
            .runtime_resume = mmc_runtime_resume,
            .power_restore = mmc_power_restore,
            .alive = mmc_alive,
            .shutdown = mmc_shutdown,
          };
        mmc_select_voltage(host, ocr) //屏蔽掉不支持的任何电压并选择最低电压
          mmc_power_cycle(host, ocr)
            mmc_power_off(host) //断电
              host->ios.clock = 0;
              host->ios.vdd = 0;
              host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
              host->ios.chip_select = MMC_CS_DONTCARE;
              host->ios.power_mode = MMC_POWER_OFF;
              host->ios.bus_width = MMC_BUS_WIDTH_1;
              host->ios.timing = MMC_TIMING_LEGACY;
            mmc_power_up(host, ocr) //上电
              //第1步骤
              host->ios.vdd = fls(ocr) - 1;
              host->ios.chip_select = MMC_CS_DONTCARE;
              host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
              host->ios.power_mode = MMC_POWER_UP;
              host->ios.bus_width = MMC_BUS_WIDTH_1;
              host->ios.timing = MMC_TIMING_LEGACY;  
              mmc_set_ios(host);                
              //第2步骤
              host->ios.clock = host->f_init;
              host->ios.power_mode = MMC_POWER_ON;
              mmc_set_ios(host);
        mmc_init_card(host, rocr, NULL)
          mmc_set_bus_mode(host, MMC_BUSMODE_OPENDRAIN) //设置总线模式,开路
          mmc_go_idle(host);
          mmc_send_op_cond(host, ocr | (1 << 30), &rocr);
            struct mmc_command cmd = {0};
            cmd.opcode = MMC_SEND_OP_COND;
            cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
            cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
            mmc_wait_for_cmd(host, &cmd, 0)
          mmc_all_send_cid(host, cid) //获取cid
            struct mmc_command cmd = {0};
            cmd.opcode = MMC_ALL_SEND_CID;
            cmd.arg = 0;
            cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;             
            mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
          mmc_set_relative_addr(card) //
            struct mmc_command cmd = {0};
            cmd.opcode = MMC_SET_RELATIVE_ADDR;
            cmd.arg = card->rca << 16;
            cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;    
            mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES)    
          mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL)
            host->ios.bus_mode = mode;
            mmc_set_ios(host);
          mmc_send_csd(card, card->raw_csd)  
            mmc_send_cxd_native(card->host, card->rca << 16,csd, MMC_SEND_CSD)  
              struct mmc_command cmd = {0};
              cmd.opcode = opcode;
              cmd.arg = arg;
              cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
              mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
          mmc_decode_csd(card)  //解析csd
            csd->max_dtr   = tran_exp[e] * tran_mant[m]; //时钟,25M
          mmc_decode_cid(card)  //解析cid
          mmc_set_dsr(host)
            struct mmc_command cmd = {0};
            cmd.opcode = MMC_SET_DSR;
            cmd.arg = (host->dsr << 16) | 0xffff;
            cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
            mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
          mmc_select_card(card)
            _mmc_select_card(card->host, card)
              struct mmc_command cmd = {0};
              cmd.opcode = MMC_SELECT_CARD;
              cmd.arg = card->rca << 16;
              cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
              mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
          mmc_get_ext_csd(card, &ext_csd) //验证时,这里出错了
            mmc_send_ext_csd(card, ext_csd)
              mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,ext_csd, 512)
                mmc_set_data_timeout(&data, card)
                mmc_wait_for_req(host, &mrq)
          mmc_read_ext_csd(card, ext_csd)
            struct mmc_ext_csd  //将ext_csd的内容解析到card结构体中(struct mmc_ext_csd),内部很复杂!!!!!!
          mmc_card_blockaddr(card)
          mmc_init_erase(card)
            mmc_set_erase_size(card)
          mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_ERASE_GROUP_DEF, 1,card->ext_csd.generic_cmd6_time)
            __mmc_switch(card, set, index, value, timeout_ms, true, true,false)
              struct mmc_command cmd = {0};
                cmd.opcode = MMC_SWITCH;
                cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |(index << 16) |(value << 8) |set;
                cmd.flags = MMC_CMD_AC;
                mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES)
          mmc_select_timing(card) //选择时序(很关键的步骤!!!!!!!!!!)
            mmc_set_bus_speed(card)
              mmc_select_hs(card)
                __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,card->ext_csd.generic_cmd6_time,true, true, true)
                mmc_set_timing(card->host, MMC_TIMING_MMC_HS)
                  host->ios.timing = timing;
                  mmc_set_ios(host);
              mmc_card_hs(card)
          mmc_card_hs200(card)
            mmc_set_clock(card->host, max_dtr)
              __mmc_set_clock(host, hz)
                host->ios.clock = hz
                  mmc_set_ios(host)
          
          mmc_select_bus_width(card) //测试总线(未执行)
            for (; idx < ARRAY_SIZE(bus_widths); idx  ) 
              mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,EXT_CSD_BUS_WIDTH,ext_csd_bits[idx],card->ext_csd.generic_cmd6_time)
              mmc_set_bus_width(host, bus_width)  //设置bus总线位数
                host->ios.bus_width = width;
                mmc_set_ios(host);
              mmc_bus_test(card, bus_width)
                mmc_send_bus_test(card, card->host, MMC_BUS_TEST_W, width);
          mmc_select_powerclass(card)
            __mmc_select_powerclass(card, ext_csd_bits)
  mmc->ops = &atmci_ops; //绑定mmc的操作接口函数,见下
  mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); //向上取整, #define DIV_ROUND_UP(n,d) (((n)   (d) - 1) / (d))
  mmc->f_max = host->bus_hz / 2;
  if ((slot_data->bus_width >= 4) && host->caps.has_rwproof) //最新的内核有更新,要注意同步!!!!!!!!!!!!!!!!!!!!!!!!!
    mmc->caps |= MMC_CAP_4_BIT_DATA;
  
  //检测mmc卡是否存在
  set_bit(ATMCI_CARD_PRESENT, &slot->flags); //假设卡存在,然后进行验证
  if (gpio_is_valid(slot->detect_pin)) {
  ...
  
  //检测mmc卡是否写保护
  if (gpio_is_valid(slot->wp_pin)) {
  ...
  
  //mmc增加电源调节
  mmc_regulator_get_supply(mmc);
  
  //配置定时器和中断,用于探测卡的状态
  if (gpio_is_valid(slot->detect_pin))
    setup_timer(&slot->detect_timer, atmci_detect_change,(unsigned long)slot);
      atmci_detect_change
        if (present != present_old)  //卡当前状态与之前状态比较
          dev_dbg(&slot->mmc->class_dev, "card %s\n", present ? "inserted" : "removed");
          if (!present)
            clear_bit(ATMCI_CARD_PRESENT, &slot->flags);
          else
            set_bit(ATMCI_CARD_PRESENT, &slot->flags);
          if (mrq == host->mrq)
            switch (host->state)
            case STATE_IDLE:
            case STATE_SENDING_CMD:
            case STATE_DATA_XFER:
            case STATE_WAITING_NOTBUSY:
            case STATE_SENDING_STOP:
            case STATE_END_REQUEST:
          else
            list_del(&slot->queue_node);
            mmc_request_done(slot->mmc, mrq);
        
    ret = request_irq(gpio_to_irq(slot->detect_pin), atmci_detect_interrupt, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "mmc-detect", slot);
      atmci_detect_interrupt
        mod_timer(&slot->detect_timer, jiffies   msecs_to_jiffies(20)); //探测到mmc管脚的变化(即热插拔),启动定时器

9.初始化debugfs文件系统

atmci_init_debugfs
  node = debugfs_create_file("regs", S_IRUSR, root, host,&atmci_regs_fops);
  node = debugfs_create_u32("state", S_IRUSR, root, (u32 *)&host->state);
  node = debugfs_create_x32("pending_events", S_IRUSR, root,(u32 *)&host->pending_events);
  node = debugfs_create_x32("completed_events", S_IRUSR, root,(u32 *)&host->completed_events);

10.提供给上层的访问数据接口

//以下是数据请求发送流程
static const struct mmc_host_ops atmci_ops = {
  .request  = atmci_request, //见下分析
  .set_ios  = atmci_set_ios,
  .get_ro   = atmci_get_ro,
  .get_cd   = atmci_get_cd,
  .enable_sdio_irq = atmci_enable_sdio_irq,
};
atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
  atmci_queue_request(struct atmel_mci *host, struct atmel_mci_slot *slot, struct mmc_request *mrq)
    if (host->state == STATE_IDLE)   //如果 atmci_tasklet_func 任务机制中的状态机为空闲 STATE_IDLE 就直接启动发送
      host->state = STATE_SENDING_CMD
      atmci_start_request(host, slot);
        host->prepare_data(host, data) //host->prepare_data = &atmci_prepare_data_dma;
          atmci_prepare_data
            host->sg = data->sg;  //以下是DMA数据准备
            host->sg_len = data->sg_len;
            host->data = data;
            host->data_chan = NULL;
            desc->callback = atmci_dma_complete; //DMA数据完成回调函数
              atmci_set_pending(host, EVENT_XFER_COMPLETE); //设置 EVENT_XFER_COMPLETE
              tasklet_schedule(&host->tasklet);        //任务调度
        host->submit_data(host, data)  //host->submit_data = &atmci_submit_data_dma;
        
        mod_timer(&host->timer, jiffies    msecs_to_jiffies(2000)); //启动软定时器
    else  //否则添加到 slot->queue_node 队列中
      list_add_tail(&slot->queue_node, &host->queue);
//配置io总线      
static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
  //总线位宽初始化
  switch (ios->bus_width) { 
  case MMC_BUS_WIDTH_1:
    slot->sdc_reg |= ATMCI_SDCBUS_1BIT;
    break;
  case MMC_BUS_WIDTH_4:
    slot->sdc_reg |= ATMCI_SDCBUS_4BIT;
    break;
  case MMC_BUS_WIDTH_8:
    slot->sdc_reg |= ATMCI_SDCBUS_8BIT;
    break;
  }
  //时钟初始化
  if (ios->clock) {
  unsigned int clock_min = ~0U;
  u32 clkdiv;
  ...
  //电源初始化
  switch (ios->power_mode) {
  case MMC_POWER_OFF:
    if (!IS_ERR(mmc->supply.vmmc))
      mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
    break;
  case MMC_POWER_UP:
    set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
    if (!IS_ERR(mmc->supply.vmmc))
      mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
    break;
    ...
//获取mmc读写标识 
static int atmci_get_ro(struct mmc_host *mmc) 
  read_only = gpio_get_value(slot->wp_pin);
  dev_dbg(&mmc->class_dev, "card is %s\n", read_only ? "read-only" : "read-write");
//获取卡是否存在
static int atmci_get_cd(struct mmc_host *mmc)
  present = !(gpio_get_value(slot->detect_pin) ^ slot->detect_is_active_high);
  dev_dbg(&mmc->class_dev, "card is %spresent\n", present ? "" : "not ");
//中断使能和禁止
static void atmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
  if (enable)
    atmci_writel(host, ATMCI_IER, slot->sdio_irq);
  else
    atmci_writel(host, ATMCI_IDR, slot->sdio_irq);

11.启动信息

Mar 16 17:56:08 kernel: atmci_probe: run here0
Mar 16 17:56:08 kernel: atmci_of_init(): pdata->slot[0].bus_width = 8
Mar 16 17:56:08 kernel: atmci_probe(): host->bus_hz=132000000
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: version: 0x505
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: using dma0chan5 for DMA transfers
Mar 16 17:56:08 kernel: atmci_init_slot(): slot->sdc_reg=0x00000000, mmc->ios.bus_width=8
bus_width=8, detect_pin=-2, detect_is_active_high=false, wp_pin=-2
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: No vmmc regulator found
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: No vqmmc regulator found
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 0Hz busmode 2 powermode 1 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 0Hz bm PP pm UP vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: Atmel MCI controller at 0xf0000000 irq 25, 1 slots
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 1 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here1
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here2
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here3
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here5
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here6
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 1 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 1 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm OD pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 400000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
OK
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 400000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_decode_csd(): run here csd->max_dtr=25000000, tran_exp[e]=1000000, tran_mant[m]=25
Mar 16 17:56:08 kernel: mmc_init_card(): run here13
Mar 16 17:56:08 kernel: mmc0: BKOPS_EN bit is not set
Mar 16 17:56:08 kernel: mmc_init_card(): run here15
Mar 16 17:56:08 kernel: mmc_select_timing: run here 4 err=0
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 0 timing 0
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 25000000Hz bm PP pm ON vdd 21 width 1 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=0, slot->sdc_reg=0x00000000
Mar 16 17:56:08 kernel: mmc_init_card(): card->host->ios.timing=0
Mar 16 17:56:08 kernel: mmc_init_card(): run here20
Mar 16 17:56:08 kernel: mmc_select_bus_width: host->caps=0x0000006d
Mar 16 17:56:08 kernel: mmc_select_bus_width(): idx=0, bus_width=3
Mar 16 17:56:08 kernel: mmc_set_ios(): mmc0: clock 25000000Hz busmode 2 powermode 2 cs 0 Vdd 21 width 3 timing 0
(CRON) STARTUP (1.4.12)
Mar 16 17:56:08 kernel: atmel_mci f0000000.mmc: sdc set ios: clk 25000000Hz bm PP pm ON vdd 21 width 8 timing LEGACY(SDR12) dt B
Mar 16 17:56:08 kernel: atmci_set_ios(): ios->bus_width=3, slot->sdc_reg=0x000000c0
(CRON) INFO (Syslog will be used instead of sendmail.)
Mar 16 17:56:08 kernel: mmc_init_card(): run here21
(CRON) INFO (RANDOM_DELAY will be scaled with factor 12% if used.)
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here7
Mar 16 17:56:08 kernel: mmc0: new MMC card at address 0001
Mar 16 17:56:08 kernel: mmcblk0: mmc0:0001 IS032G 29.1 GiB 
(root) BAD FILE MODE (/etc/crontab)
Mar 16 17:56:08 kernel: mmcblk0boot0: mmc0:0001 IS032G partition 1 4.00 MiB
Mar 16 17:56:08 kernel: mmcblk0boot1: mmc0:0001 IS032G partition 2 4.00 MiB
Mar 16 17:56:08 kernel:  mmcblk0: unknown partition table
Mar 16 17:56:08 kernel: mmc_attach_mmc(): run here8

12. eMMC获取CSD

4.eMMC调试输出CSD获取
Mar 17 08:35:21 kernel: mmc_decode_csd(): run here structure=3, mmca_vsn=4, mmca_vsn=4, max_dtr=25000000, cmdclass=000000f5, read_blkbits=9, read_partial=0, write_misalign=0, read_misalign=0, write_blkbits=9, write_partial=0, erase_size=1024

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibehha
系列文章
更多 icon
同类精品
更多 icon
继续加载