Jump to content

Mainline:Exynos 4/EMMC and SDHCI: Difference between revisions

From dissonant.dev wiki
No edit summary
No edit summary
 
Line 7: Line 7:
Converting from those structs:
Converting from those structs:


=== <code>exynos4_mshc_pdata</code> ===
== <code>exynos4_mshc_pdata</code> ==


'''Only if your device has <code>CONFIG_EXYNOS4_DEV_MSHC</code> enabled.'''
'''Only if your device has <code>CONFIG_EXYNOS4_DEV_MSHC</code> enabled.'''
Line 15: Line 15:
* <code>int_power_gpio</code>: note down the GPIO and read on to “Regulator” section.
* <code>int_power_gpio</code>: note down the GPIO and read on to “Regulator” section.


=== <code>exynos_dwmci_pdata</code> ===
== <code>exynos_dwmci_pdata</code> ==


'''Only if your device has <code>CONFIG_EXYNOS4_DEV_DWMCI</code> enabled.'''
'''Only if your device has <code>CONFIG_EXYNOS4_DEV_DWMCI</code> enabled.'''
Line 30: Line 30:
* Clocks are already set up
* Clocks are already set up


=== Pinctrl ===
== Pinctrl ==


Pinctrl may need to be set up according to width; see <code>exynos_dwmci_cfg_gpio</code> for DWMCI, <code>arch/arm/mach-exynos/setup-mshci-gpio.c</code> for MSHCI. There are premade pinctrl defaults <code>sdX_bus1</code>, <code>sdX_bus4</code> and <code>sdX_bus8</code> for width 1, 4 and 8 respectively (see midas DTSI for an example).
Pinctrl may need to be set up according to width; see <code>exynos_dwmci_cfg_gpio</code> for DWMCI, <code>arch/arm/mach-exynos/setup-mshci-gpio.c</code> for MSHCI. There are premade pinctrl defaults <code>sdX_bus1</code>, <code>sdX_bus4</code> and <code>sdX_bus8</code> for width 1, 4 and 8 respectively (see midas DTSI for an example).
Line 36: Line 36:
Replace <code>X</code> with 0 or 4, depending on the contents of <code>exynos_dwmci_cfg_gpio</code> (or equivalent <code>.cfg_gpio</code> member of <code>exynos_dwmci_pdata</code> struct) function: if for width 8 it does <code>s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));</code>, then 4, else 0. (The only difference between these two is the pin-function that’s set, see <code>exynos4x12-pinctrl.dtsi</code>.) In width 8, add both <code>bus4</code> and <code>bus8</code> (each has 4 pins, coming together to 8 pins total).  
Replace <code>X</code> with 0 or 4, depending on the contents of <code>exynos_dwmci_cfg_gpio</code> (or equivalent <code>.cfg_gpio</code> member of <code>exynos_dwmci_pdata</code> struct) function: if for width 8 it does <code>s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));</code>, then 4, else 0. (The only difference between these two is the pin-function that’s set, see <code>exynos4x12-pinctrl.dtsi</code>.) In width 8, add both <code>bus4</code> and <code>bus8</code> (each has 4 pins, coming together to 8 pins total).  


=== Regulator ===
== Regulator ==


This depends on your device. Midas has a <code>VMEM_VDD_2.8V</code> regulator in its PMIC, your device might have something similar - check schematics. This will have to be enabled by the GPIO listed as <code>int_power_gpio</code> in your <code>exynos4_mshc_pdata</code> struct, probably <code>gpk0-2</code>.
This depends on your device. Midas has a <code>VMEM_VDD_2.8V</code> regulator in its PMIC, your device might have something similar - check schematics. This will have to be enabled by the GPIO listed as <code>int_power_gpio</code> in your <code>exynos4_mshc_pdata</code> struct, probably <code>gpk0-2</code>.
Line 42: Line 42:
If you’re unsure, or if there’s no such regulator in your case, then you can create a <code>regulator-fixed</code> with a min/max voltage of 2.8V and enabled/disabled by said GPIO, and give <code>sdX_cd</code> pinctrl to it, or ignore it entirely and give the <code>sdX_cd</code> pinctrl to the <code>mshc_0</code> node.
If you’re unsure, or if there’s no such regulator in your case, then you can create a <code>regulator-fixed</code> with a min/max voltage of 2.8V and enabled/disabled by said GPIO, and give <code>sdX_cd</code> pinctrl to it, or ignore it entirely and give the <code>sdX_cd</code> pinctrl to the <code>mshc_0</code> node.


=== Timing values ===
== Timing values ==


Timing values are written to the <code>clksel</code> register on the MMC host, at offset <code>0x9c</code>. The timing values in mainline are the <code>sample</code> and <code>drive</code> values respectively.
Timing values are written to the <code>clksel</code> register on the MMC host, at offset <code>0x9c</code>. The timing values in mainline are the <code>sample</code> and <code>drive</code> values respectively.

Latest revision as of 17:45, 21 January 2025

This page contains notes regarding porting downstream kernel SDHCI/EMMC data to mainline.

Main EMMC node is mshc_0; the data for it is stored in structs exynos_dwmci_pdata and exynos4_mshc_pdata.

See Documentation/devicetree/bindings/mmc/mmc-controller.yaml.

Converting from those structs:

exynos4_mshc_pdata

Only if your device has CONFIG_EXYNOS4_DEV_MSHC enabled.

  • cd_type: probably S3C_MSHCI_CD_PERMANENT, in which case, non-removable;
  • caps: see mmc-controller.yaml, they’re pretty much the same
  • int_power_gpio: note down the GPIO and read on to “Regulator” section.

exynos_dwmci_pdata

Only if your device has CONFIG_EXYNOS4_DEV_DWMCI enabled.

  • quirks:
    • DW_MCI_QUIRK_BROKEN_CARD_DETECTION -> broken-cd;
    • DW_MCI_QUIRK_HIGHSPEED -> cap-mmc-highspeed
  • bus_hz -> clock-frequency: <FIXME>;
  • caps: see mmc-controller.yaml, they’re pretty much the same
    • MMC_CAP_CMD23 is enabled by default, no need to add it
    • MMC_CAP_8_BIT_DATA is bus-width = <8>;
  • detect_delay_ms -> card-detect-delay = <FIXME>;
  • fifo-depth -> fifo-depth = <0xFIXME>; (note: 0x80 is default, so skip this if it’s 0x80 on your device)
  • Clocks are already set up

Pinctrl

Pinctrl may need to be set up according to width; see exynos_dwmci_cfg_gpio for DWMCI, arch/arm/mach-exynos/setup-mshci-gpio.c for MSHCI. There are premade pinctrl defaults sdX_bus1, sdX_bus4 and sdX_bus8 for width 1, 4 and 8 respectively (see midas DTSI for an example).

Replace X with 0 or 4, depending on the contents of exynos_dwmci_cfg_gpio (or equivalent .cfg_gpio member of exynos_dwmci_pdata struct) function: if for width 8 it does s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(4));, then 4, else 0. (The only difference between these two is the pin-function that’s set, see exynos4x12-pinctrl.dtsi.) In width 8, add both bus4 and bus8 (each has 4 pins, coming together to 8 pins total).

Regulator

This depends on your device. Midas has a VMEM_VDD_2.8V regulator in its PMIC, your device might have something similar - check schematics. This will have to be enabled by the GPIO listed as int_power_gpio in your exynos4_mshc_pdata struct, probably gpk0-2.

If you’re unsure, or if there’s no such regulator in your case, then you can create a regulator-fixed with a min/max voltage of 2.8V and enabled/disabled by said GPIO, and give sdX_cd pinctrl to it, or ignore it entirely and give the sdX_cd pinctrl to the mshc_0 node.

Timing values

Timing values are written to the clksel register on the MMC host, at offset 0x9c. The timing values in mainline are the sample and drive values respectively.

For tab3 downstream, they seem to be set in arch/arm/mach-exynos/dev-dwmci.c, and are the same for all devices.

For MSHCI, the values are hardcoded in drivers/mmc/host/mshci.c line 1252 and onwards.

DDR value is for DDR_50 mode, SDR is for non-DDR_50. Both of the aforementioned files have ifs for checking this.

To decode a CLKSEL value, run this python script

value = 0x00010001  # CHANGE THIS

print("Sample:", (clksel_val >> 0) & 7)
print("Drive:", (clksel_val >> 8) & 7)
print("Divider:", (clksel_val >> 16) & 7)

However, the sample value seems to be tuned at runtime using the built-in tune function. Unclear how this works yet, TODO.

Divider is samsung,dw-mshc-ciu-div, but is ignored for Exynos4412 anyways, TODO? See drivers/mmc/host/dw_mmc-exynos.c in mainline. Sample and drive are passed to the timing values in that order.

…Our best bet is probably to get those values from a running device, somehow…