This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

OMAP L138 MMC 2 register access issue

Other Parts Discussed in Thread: DA8XX, OMAP-L138

Hi,

Currently we are writing SDIO driver for OMAP L138 for MMC 1 and MMC 2 controllers. We have tested SDIO interface over MMC 1 and it is working fine for me. When we are trying to test SDIO interface over MMC2 by changing the base address. We observe that we can not able to write to the controller registers.

Please find the code to get the MMC2 base address:

#define OMAP_HSMMC1_BASE                0x01C40000  /* MMC1 Controler base address */
#define OMAP_HSMMC2_BASE                0x01E1B000  /* MMC2 Controler base address */

 

mem = request_mem_region(OMAP_HSMMC2_BASE, SZ_4K, "davinci_mmc1");

 g_drv.regBase =  ioremap(mem->start, SZ_4K);

g_drv.clk = clk_get(&pdev->dev, "MMCSDCLK");

 

From Data sheet it seems that there is only one functional clock for MMC 1 and MMC 2. Please correct me if i am wrong.

Do i need to do any more configuration for MMC 2 controller over the MMC 1?

 

Best regards

Sanjay

 

  • Sanjay

    What platform are you using for development and debug?

    Please also make sure that

    1) The clock is enabled to MMC/SD1 module. This is managed by PSC1 LPSC18. You should be quickly able to verify this , if reading the MMC/SD1 registers show you non-zero values. If the reads to MMRs return zero, they typically imply the clocks to the module might've not been enabled ( e.g MMCLK CLKRT field by default should show 0xFF)

    2) Make sure that you have configured the PINMUX registers to appropriately bring out the MMC/SD1 IOs.

    Hope this helps.
    Regards

    Mukul

  • Hi Mukul,

    Thanks for your replay.

    I am using OMAP L138 ARM based platform. Here MMC 2 is not working properly.

    As i posted in the earlier, my SDIO interface is working fine for MMC1, but when i change MMC 2 base address, i am not able to access MMC2  register. Currently i am using "clk_get(&pdev->dev, "MMCSDCLK");" API to get the MMC2  clock. I dumped the register but content of all the registers are zero. I could not able to write to MMC 2 controller register.

    From the OMAP L138 data sheet, i found there is only one clock for MMC 1 and MMC 2.

    MMCCLK CLKRT register value also shows zero's. I have done the all the pin muxing for MMC2 interface.

     

    Is there any more clock is available to set for MMC2?

     

  • Sanjay,

    I think Mukul was asking if you are using a custom PCB or if you are using the EVM.

    The MMC/SD peripherals share a common internal reference clock, however each module has a separate Power and Sleep Controller (PSC) signal that clock-gates the modules for power savings.  MMC/SD0 is on PSC0, #5.  MMC/SD1 is on PSC1, #18.  If the module is clock-gated through PSC, you will not be able to write to the registers and reads will return 0's.

    -Tommy

  • The device.c in ubl for OMAPL1x8 has the necessary functions that you can use to enable the second MMC/SD.

    void DEVICE_LPSCTransition(Uint8 pscnum, Uint8 module, Uint8 domain, Uint8 state)

    I believe by default the clocks to second MMC/SD is not enabled and I don't think the ubl etc are enabling the second MMC/SD clocks.

    Since you indicated that you are reading back all zeros, you do need to make sure you have turned on the clocks via the on chip power sleep controller (PSC).

    Regards

    Mukul

  • Hi Mukul,

    I am using "linux-03.20.00.12" kernel for OMAP L138. I have done the following step to enable MMC 2:

    In the "arch/arm/mach-davinci/include/mach/psc.h" file add the PSC entry as per date sheet:
    #define DA8XX_LPSC1_MMC_SD         18

     

    In the "arch/arm/mach-davinci/da850.c" file added the structure as:

    static struct clk mmcsd_clk1 = {
            .name           = "mmcsd1",
            .parent         = &pll0_sysclk2,
            .lpsc           = DA8XX_LPSC1_MMC_SD,
    };

     

    In the "static struct clk_lookup da850_clks[]" structure added the entry for PSC 1

    CLK("davinci_mmc.1",    NULL,           &mmcsd_clk1),

     

    After follow the above procedure, Still we found that MMC 2 controller is not enabled.

    Please let me know is there anything i am missing?

     

    Best Regards

    Sanjay

    Best Regards

    Sanjay

     

  • Sanjay,

    You also need to register a platform device for the second MMC/SD controller.

    Here is a link to discussion on enabling MMCSD1 on OMAP-L138: http://www.mail-archive.com/davinci-linux-open-source@linux.davincidsp.com/msg17926.html

    Thanks,
    Sekhar

  • Hi Sakhar,

    My SDIO driver is not part of kernel, i am writing outside the kernel and it is independant of kernel. For me MMC 0 is working fine but when i am changing the for MMC 1 base address in place of MMC 0. I found that MMC 1 controler all registers are displaying zero.

     

    Please find the log for MMC 1 controler registers display:

    =====================================

    root@arago:~# insmod sdio.ko
    sdio_probe: Called
    Base Reg: 0xfee1b000
     ***************************************************
     *     OMAP MMC Host controller registers dump:    *
     ***************************************************
    Base Address:0xfee1b000
    MMCCTL =  0x00000000
    MMCCLK =  0x00000000
    MMCST0 =  0x00000000
    MMCST1 =  0x00000000
    MMCIM =  0x00000000
    MMCTOR =  0x00000000
    MMCTOD =  0x00000000
    MMCBLEN =  0x00000000
    MMCNBLK =  0x00000000
    MMCNBLC =  0x00000000
    MMCDRR =  0x00000000
    MMCDXR =  0x00000000
    MMCCMD =  0x00000000
    MMCARGHL =  0x00000000
    MMCRSP01 =  0x00000000
    MMCRSP23 =  0x00000000
    MMCRSP45 =  0x00000000
    MMCRSP67 =  0x00000000
    MMCDRSP =  0x00000000
    MMCCIDX =  0x00000000
    SDIOCTL =  0x00000000
    SDIOST0 =  0x00000000
    SDIOIEN =  0x00000000
    SDIOIST =  0x00000000
    MMCFIFOCTL =  0x00000000

    =====================================

     

    I added for MMC 1 platform device but the result is remain same. Please find the platform device code:

    =====================================

    static struct resource da8xx_mmcsd1_resources[] = {
            {               /* registers */
                    .start  = DA8XX_MMCSD1_BASE,
                    .end    = DA8XX_MMCSD1_BASE + SZ_4K - 1,
                    .flags  = IORESOURCE_MEM,
            },
            {               /* interrupt */
                    .start  = IRQ_DA850_MMCSDINT0_1,
                    .end    = IRQ_DA850_MMCSDINT0_1,
                    .flags  = IORESOURCE_IRQ,
            },
            {               /* DMA RX */
                    .start  = EDMA_CTLR_CHAN(1, 28),
                    .end    = EDMA_CTLR_CHAN(1, 28),
                    .flags  = IORESOURCE_DMA,
            },
            {               /* DMA TX */
                    .start  = EDMA_CTLR_CHAN(1, 29),
                    .end    = EDMA_CTLR_CHAN(1, 29),
                    .flags  = IORESOURCE_DMA,
            },
    };

    static struct platform_device da8xx_mmcsd1_device = {
            .name           = "davinci_mmc1",
            .id             = 0,
            .num_resources  = ARRAY_SIZE(da8xx_mmcsd1_resources),
            .resource       = da8xx_mmcsd1_resources,
    };

    int __init da8xx_register_mmcsd1(struct davinci_mmc_config *config)
    {
            da8xx_mmcsd1_device.dev.platform_data = config;
            return platform_device_register(&da8xx_mmcsd1_device);
    }

    =====================================

     

    I feel that MMC 1 control is not getting enable. Please let me know is there any procedure to enable MMC 1 controller?

     

     

  • Sanjay,

    Can you read back the MMC/SD1 MDSTAT register to make sure that the peripheral is enabled as expected?

    The address should be:  0x01E27848   [ 0x01E27800 + (4 * 18) ]

    -Tommy

  • Hi Tommy,

    I read the MDSTAT register and please find the virtual address and content of the MDSTAT register:

    Virtual address-> MDSTAT ADRESS: 0xfee27848
    MDSTAT CONTENT: 0xa00 (9th and 11th bit is enable)

    Let me know do we need to configure any more registers to enable MMC/SD1controller?

    Best Regards

    Sanjay

  • Sanjay,

    It looks like the module is not enabled.  If you look at the register definition for MDSTAT in the system reference guide, you will see that the MDSTAT[STATE] field for an enabled module is 0x3 (typical value is 0x1E03).

    Can you try to change the state through the DSP or CCS GEL?

    -Tommy

  • Hi Tommy,

    We are working on ARM based Linux platform. We don't have option to change the state using DSP or CCS GEL.

    Is there any other alternative way to do this, please let me know the procedure to fix this issue?

     

    Thanks regards

    Sanjay

  • Sanjay,

        The other option is to enable MMC/SD1 (you referred it as MMC2) in user boot loader (UBL).

     

    Sanjay Kumar said:

    Hi Tommy,

    We are working on ARM based Linux platform. We don't have option to change the state using DSP or CCS GEL.

    Is there any other alternative way to do this, please let me know the procedure to fix this issue?

     

    Thanks regards

    Sanjay

     

  • Hi Sanjay

    Not sure what the issue on your setup  is. Between Sekhar's and Tommy/my responses it would seem like it should've worked. The issue is the clock to the MMC/SD module is not enabled, and I guess despite doing what is required from a platform registration and other stuff you still are not able to get the clock enabled.

    Maybe we are still missing something in your driver creation setup.

    There are no device issues with that MMC/SD port, and the module clock via LPSC18 is all that you should need to enable the MMC/SD module.

    I wonder if you could try to modify the UBL to enable the MMC/SD1 by default, to see if it helps?

    The code in device.c would look something like this (I might not have the latest version)

     

    void DEVICE_PSCInit()
    {                                                                   
      Uint32 i;
     
      // PSC0, domain 0 init
      while ((PSC0->PTSTAT) & 0x00000001);

      for( i = 3 ; i <= 4 ; i++ )
        if((PSC0->MDCTL[i] & 0x1F) != PSC_ENABLE)
          PSC0->MDCTL[i] = (PSC0->MDCTL[i] & 0xFFFFFFE0) | PSC_ENABLE;

      if((PSC0->MDCTL[7] & 0x1F) != PSC_ENABLE)
          PSC0->MDCTL[7] = (PSC0->MDCTL[7] & 0xFFFFFFE0) | PSC_ENABLE;

      if((PSC0->MDCTL[8] & 0x1F) != PSC_ENABLE)
          PSC0->MDCTL[8] = (PSC0->MDCTL[8] & 0xFFFFFFE0) | PSC_ENABLE;

      for( i =  9; i <= 12 ; i++ )
        if((PSC0->MDCTL[i] & 0x1F) != PSC_ENABLE)
          PSC0->MDCTL[i] = (PSC0->MDCTL[i] & 0xFFFFFFE0) | PSC_ENABLE;
       
      // Do Always-On Power Domain Transitions
      PSC0->PTCMD |= 0x00000001;
      while ((PSC0->PTSTAT) & 0x00000001);
     
      // PSC1, domain 1 init
      while ((PSC1->PTSTAT) & 0x00000001);

      if((PSC1->MDCTL[3] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[3] = (PSC1->MDCTL[3] & 0xFFFFFFE0) | PSC_ENABLE;

      if((PSC1->MDCTL[6] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[6] = (PSC1->MDCTL[6] & 0xFFFFFFE0) | PSC_ENABLE;

      for( i = 12 ; i <= 13 ; i++ )
        if((PSC1->MDCTL[i] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[i] = (PSC1->MDCTL[i] & 0xFFFFFFE0) | PSC_ENABLE;

      if((PSC1->MDCTL[26] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[26] = (PSC1->MDCTL[26] & 0xFFFFFFE0) | PSC_ENABLE;

      if((PSC1->MDCTL[31] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[31] = (PSC1->MDCTL[31] & 0xFFFFFFE0) | PSC_ENABLE;
       
      // Do Always-On Power Domain Transitions
      PSC1->PTCMD |= 0x00000001;
      while ((PSC1->PTSTAT) & 0x00000001);
    }

    You should be able to just add another set of lines for MMC/SD1

    if((PSC1->MDCTL[18] & 0x1F) != PSC_ENABLE)
          PSC1->MDCTL[18] = (PSC1->MDCTL[18] & 0xFFFFFFE0) | PSC_ENABLE;

    Please see if this helps?

    Trying to get more Linux experts to look at your query to see what might be amiss in your setup.

    Regards

    Mukul

  • Hi Mukul,

    Thanks for your relay.

    To enable the clock for MMC 2 we have the below procedure. However this procedure is not helping to enable MMC 2 clock.

     

    #define DA8XX_LPSC1_MMC_SD 18

     

    In the "arch/arm/mach-davinci/da850.c" file added the structure as:

     

    static struct clk mmcsd_clk1 = {
            .name           = "mmcsd1",
            .parent         = &pll0_sysclk2,
            .lpsc           = DA8XX_LPSC1_MMC_SD,
    };

     

     

     

    static struct clk_lookup da850_clks[] = {

            CLK(NULL,               "ref",          &ref_clk),

            CLK(NULL,               "pll0",         &pll0_clk),

            CLK(NULL,               "pll0_aux",     &pll0_aux_clk),

             CLK(NULL,               "pll0_sysclk2", &pll0_sysclk2),

             CLK(NULL,               "pll0_sysclk3", &pll0_sysclk3),

             CLK(NULL,               "pll0_sysclk4", &pll0_sysclk4),

             CLK(NULL,               "pll0_sysclk5", &pll0_sysclk5),

             CLK(NULL,               "pll0_sysclk6", &pll0_sysclk6),

             CLK(NULL,               "pll0_sysclk7", &pll0_sysclk7),

             CLK(NULL,               "pll1",         &pll1_clk),

             CLK(NULL,               "pll1_aux",     &pll1_aux_clk),

             CLK(NULL,               "pll1_sysclk2", &pll1_sysclk2),

             CLK(NULL,               "pll1_sysclk3", &pll1_sysclk3),

             CLK(NULL,               "pll1_sysclk4", &pll1_sysclk4),

             CLK(NULL,               "pll1_sysclk5", &pll1_sysclk5),

             CLK(NULL,               "pll1_sysclk6", &pll1_sysclk6),

             CLK(NULL,               "pll1_sysclk7", &pll1_sysclk7),

             CLK("i2c_davinci.1",    NULL,           &i2c0_clk),

             CLK(NULL,               "timer0",       &timerp64_0_clk),

             CLK("watchdog",         NULL,           &timerp64_1_clk),

             CLK(NULL,               "arm_rom",      &arm_rom_clk),

             CLK(NULL,               "tpcc0",        &tpcc0_clk),

             CLK(NULL,               "tptc0",        &tptc0_clk),

             CLK(NULL,               "tptc1",        &tptc1_clk),

             CLK(NULL,               "tpcc1",        &tpcc1_clk),

             CLK(NULL,               "tptc2",        &tptc2_clk),

             CLK(NULL,               "uart0",        &uart0_clk),

             CLK(NULL,               "uart1",        &uart1_clk),

             CLK(NULL,               "uart2",        &uart2_clk),

             CLK(NULL,               "aintc",        &aintc_clk),

             CLK(NULL,               "gpio",         &gpio_clk),

             CLK("i2c_davinci.2",    NULL,           &i2c1_clk),

             CLK(NULL,               "emif3",        &emif3_clk),

             CLK(NULL,               "arm",          &arm_clk),

             CLK(NULL,               "rmii",         &rmii_clk),

             CLK("davinci_emac.1",   NULL,           &emac_clk),

             CLK("davinci-mcasp.0",  NULL,           &mcasp_clk),

             CLK("da8xx_lcdc.0",     NULL,           &lcdc_clk),

             CLK("davinci_mmc.0",    NULL,           &mmcsd_clk),

    CLK("NULL",               "mmcsd1",           &mmcsd_clk1),

             CLK(NULL,               "aemif",        &aemif_clk),

             CLK(NULL,               NULL,           NULL),

     };

     

    Apart form this configuration, do we need to set any more register?

     

    Best Regards

    Sanjay

  • Sanjay

    Sanjay Kumar said:
    Apart form this configuration, do we need to set any more register?

    I am not sure. From the face of it , it looks ok, but if something else is missing I hope the Linux team comment /share additional pointers (they have been made aware of your forum post). Based on the link Sekhar provided it would seem like it has been tried and worked successfully before.

    However since it still doesn't seem to work for you, that is why we were recommending to explore if  you could directly enable the MMC/SD by modifying the UBL? Is that not an option that you could test out?

    Regards

    Mukul

  • Sanjay,

    The MMC/SD clocks are enabled by the clk_enable() call in davinci_mmcsd_probe() function of drivers/mmc/host/davinci_mmc.c

    Can you please make sure that is getting called for MMCSD1? As pointed out by Tommy, from MDSTAT register, it doesnt look like MMCSD1 clock is enabled.

    Thanks,

    Sekhar

     

  • Hi Sekhar,

    Currently i modified the kernel files to register the MMC 2 clock as given below:

     

    Note: Text in red color is modified to support MMC 2.

    In "arch/arm/mach-davinci/da850.c" file:

    static struct clk mmcsd_clk = {
            .name           = "mmcsd",
            .parent         = &pll0_sysclk2,
            .lpsc           = DA8XX_LPSC0_MMC_SD,
    };

    static struct clk mmcsd_clk1 = {
            .name           = "mmcsd1",
            .parent         = &pll0_sysclk2,
            .lpsc           = DA8XX_LPSC1_MMC_SD,
    };

     

    In the "static struct clk_lookup da850_clks[]" structure:

     CLK("da8xx_lcdc.0",     NULL,           &lcdc_clk),
            CLK("davinci_mmc.0",    NULL,           &mmcsd_clk),
            CLK(NULL,               "mmcsd1",       &mmcsd_clk1),
            CLK(NULL,               "aemif",        &aemif_clk),

     

    To Enable the clock i am calling function clk_enable() from my MMC 2 driver, which is out side the kernel.

    Please find the function call done from my code to enable MMC 2 clock:

     g_drv.clk = clk_get(&pdev->dev, "mmcsd1");

    clk_enable(g_drv.clk);

    g_drv.input_clk = clk_get_rate(g_drv.clk);

     

    Please let me know the procedure that i am following, is proper to enable MMC 2 clock?

     

    Best Regards

    Sanjay


     

  • Sanjay,

    The code looks correct to me. It doesn't work?

    Thanks,

    Sekhar

  • Hi Sekhar,

    The posted code is not working.

    Is there any alternative way to check the MMC 2 module status?

    Best Regards

    Sanjay

  • Hi Mukul,

    We went through the UBL(uboot-03.20.00.12) and kernel (linux-03.20.00.12) code.  However we couldnt see any provision to change the PSC code to enable MDCTL. Looks like our base code we are seeing is not similar. Can you please let us know your version of code.

    Best Regards

    Sanjay

  • The device.c file I was referring to was part of the PSP release that you can download from

    http://software-dl.ti.com/dsps/dsps_public_sw/psp/LinuxPSP/DaVinci_03_20/03_20_00_12/index_FDS.html

    The ubl code is here:

    DaVinci-PSP-SDK-03.20.00.12\DaVinci-PSP-SDK-03.20.00.12\src\boot-strap\armubl-03.20.00.12.tar\armubl-03.20.00.12\src\omapl1x8

     

    Regards

    Mukul


  • Another long shot (as I am not the subject matter expert on this), for all peripherals under PSC1 control I see an additional parameter .gpsc=1 specified, I wonder if this helps

     

    static struct clk mmcsd_clk1 = {
            .name           = "mmcsd1",
            .parent         = &pll0_sysclk2,
            .lpsc         
      = DA8XX_LPSC1_MMC_SD,

           .gpsc        = 1,


    };

  • Hi,Mukul Bhatnagar :

          I am facing to the same problem wtih you, I edit the code as you did, the mmc1(mmc2 you referenced )module can not work.

    Can you give me some advices? 

    best regards!