MMC core:

- Initial support for SD express card/host
 
 MMC host:
  - mxc: Convert the driver to DT-only
  - mtk-sd: Add HS400 enhanced strobe support
  - mtk-sd: Add support for the MT8192 SoC variant
  - sdhci-acpi: Allow changing HS200/HS400 driver strength for AMDI0040
  - sdhci-esdhc-imx: Convert the driver to DT-only
  - sdhci-pci-gli: Improve performance for HS400 mode for GL9763E
  - sdhci-pci-gli: Reduce power consumption for GL9755
  - sdhci-xenon: Introduce ACPI support
  - tmio: Fix command error processing
  - tmio: Inform the core about the max_busy_timeout
  - tmio/renesas_sdhi: Support custom calculation of busy-wait time
  - renesas_sdhi: Reset SCC only when available
  - rtsx_pci: Add SD Express mode support for RTS5261
  - rtsx_pci: Various fixes and improvements for RTS5261
 
 MEMSTICK:
  - Minor fixes/improvements.
 -----BEGIN PGP SIGNATURE-----
 
 iQJLBAABCgA1FiEEugLDXPmKSktSkQsV/iaEJXNYjCkFAl/XZuAXHHVsZi5oYW5z
 c29uQGxpbmFyby5vcmcACgkQ/iaEJXNYjCnYEBAAkHWJNCUILpqAcvc8VNpo2YJ3
 vpLT1u4S3CgZ0DMJ8Oatgw6gaoTCJwX/qdXJPCCCsaiCg+H0rZATnq7/fp3CnPk+
 NZ0JYoSxLTRIkaNaOxHDkR3P7JcJKy9pxUV6rvTQMK6rRtFxv9w7xrUTNOT5GiNj
 5xB+uPrZ0AGhGdNaBU3/ZmmuCi1s8yf1B64IljqXTfQZJ6nvWbYFAWw8r4gfslfx
 NLCo1+vwTOj3ADrgOI3eafFKKnME2bRgc/o/PM/iDciJlQfHnKzcQmDKSO4Rp89a
 SVz5QYNfatfrjhgUv4DY/RsFEDlPbOiP71jKodcOSNoF5vjfNaudHhTNI1df0Pdw
 /McFtKBIisrapDMa2wXwE7fTFLDUngACTc6FaSn86PyFU0wum3XEH90aqF9KKuQp
 Ra88U/zsLUYE0jGkm6XWBsvmJHBZMTgFwXjlmdu52rnDRKccLgfCCTvb1oBGjrTj
 ZMDokgrZ74JiAHu3o0VtKLGCtNVZBjVC6TqC1ZBIrXLOpALGZGkFW8iSXgiArMX+
 NpMr9rExgobsAv02DTqWxlXLrEcUMO9IgM/TXbDQZP4hD5j1kzce9P5m59He9t/B
 UMmJc5SEgdCbMjwuBORdB0qyW0g9So880E8uuk8kw5/I7F8ONsahCsKbZntvwOrY
 s/UoF5RizRZhDJx2au4=
 =1A/T
 -----END PGP SIGNATURE-----

Merge tag 'mmc-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC updates from Ulf Hansson:
 "MMC core:
   - Initial support for SD express card/host

  MMC host:
   - mxc: Convert the driver to DT-only
   - mtk-sd: Add HS400 enhanced strobe support
   - mtk-sd: Add support for the MT8192 SoC variant
   - sdhci-acpi: Allow changing HS200/HS400 driver strength for AMDI0040
   - sdhci-esdhc-imx: Convert the driver to DT-only
   - sdhci-pci-gli: Improve performance for HS400 mode for GL9763E
   - sdhci-pci-gli: Reduce power consumption for GL9755
   - sdhci-xenon: Introduce ACPI support
   - tmio: Fix command error processing
   - tmio: Inform the core about the max_busy_timeout
   - tmio/renesas_sdhi: Support custom calculation of busy-wait time
   - renesas_sdhi: Reset SCC only when available
   - rtsx_pci: Add SD Express mode support for RTS5261
   - rtsx_pci: Various fixes and improvements for RTS5261

  MEMSTICK:
   - Minor fixes/improvements"

* tag 'mmc-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (72 commits)
  dt-bindings: mmc: eliminate yamllint warnings
  mmc: sdhci-xenon: introduce ACPI support
  mmc: sdhci-xenon: use clk only with DT
  mmc: sdhci-xenon: switch to device_* API
  mmc: sdhci-xenon: use match data for controllers variants
  dt-bindings: mmc: Fix xlnx,mio-bank property values for arasan driver
  mmc: renesas_sdhi: populate hook for longer busy_wait
  mmc: tmio: add hook for custom busy_wait calculation
  mmc: tmio: set max_busy_timeout
  dt-bindings: mmc: imx: fix the wrongly dropped imx8qm compatible string
  mmc: sdhci-pci-gli: Disable slow mode in HS400 mode for GL9763E
  mmc: sdhci: Use more concise device_property_read_u64
  memstick: r592: Fix error return in r592_probe()
  mmc: mxc: Convert the driver to DT-only
  mmc: mxs: Remove the unused .id_table
  mmc: sdhci-of-arasan: Fix fall-through warnings for Clang
  mmc: sdhci-pci-gli: Reduce power consumption for GL9755
  mmc: mediatek: depend on COMMON_CLK to fix compile tests
  mmc: pxamci: Fix error return code in pxamci_probe
  mmc: sdhci: Update firmware interface API
  ...
This commit is contained in:
Linus Torvalds 2020-12-15 15:57:25 -08:00
commit ce51c2b7ce
52 changed files with 839 additions and 454 deletions

View file

@ -147,7 +147,7 @@ properties:
xlnx,mio-bank:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 2]
enum: [0, 1, 2]
default: 0
description:
The MIO bank number in which the command and data lines are configured.

View file

@ -39,6 +39,7 @@ properties:
- fsl,imx8mn-usdhc
- fsl,imx8mp-usdhc
- fsl,imx8mq-usdhc
- fsl,imx8qm-usdhc
- fsl,imx8qxp-usdhc
- const: fsl,imx7d-usdhc

View file

@ -1,75 +0,0 @@
* MTK MMC controller
The MTK MSDC can act as a MMC controller
to support MMC, SD, and SDIO types of memory cards.
This file documents differences between the core properties in mmc.txt
and the properties used by the msdc driver.
Required properties:
- compatible: value should be either of the following.
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
"mediatek,mt8183-mmc": for mmc host ip compatible with mt8183
"mediatek,mt8516-mmc": for mmc host ip compatible with mt8516
"mediatek,mt6779-mmc": for mmc host ip compatible with mt6779
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
"mediatek,mt7622-mmc": for MT7622 SoC
"mediatek,mt7623-mmc", "mediatek,mt2701-mmc": for MT7623 SoC
"mediatek,mt7620-mmc", for MT7621 SoC (and others)
- reg: physical base address of the controller and length
- interrupts: Should contain MSDC interrupt number
- clocks: Should contain phandle for the clock feeding the MMC controller
- clock-names: Should contain the following:
"source" - source clock (required)
"hclk" - HCLK which used for host (required)
"source_cg" - independent source clock gate (required for MT2712)
"bus_clk" - bus clock used for internal register access (required for MT2712 MSDC0/3)
- pinctrl-names: should be "default", "state_uhs"
- pinctrl-0: should contain default/high speed pin ctrl
- pinctrl-1: should contain uhs mode pin ctrl
- vmmc-supply: power to the Core
- vqmmc-supply: power to the IO
Optional properties:
- assigned-clocks: PLL of the source clock
- assigned-clock-parents: parent of source clock, used for HS400 mode to get 400Mhz source clock
- hs400-ds-delay: HS400 DS delay setting
- mediatek,hs200-cmd-int-delay: HS200 command internal delay setting.
This field has total 32 stages.
The value is an integer from 0 to 31.
- mediatek,hs400-cmd-int-delay: HS400 command internal delay setting
This field has total 32 stages.
The value is an integer from 0 to 31.
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
If present,HS400 command responses are sampled on rising edges.
If not present,HS400 command responses are sampled on falling edges.
- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
error caused by stop clock(fifo full)
Valid range = [0:0x7]. if not present, default value is 0.
applied to compatible "mediatek,mt2701-mmc".
- resets: Phandle and reset specifier pair to softreset line of MSDC IP.
- reset-names: Should be "hrst".
Examples:
mmc0: mmc@11230000 {
compatible = "mediatek,mt8173-mmc", "mediatek,mt8135-mmc";
reg = <0 0x11230000 0 0x108>;
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
vmmc-supply = <&mt6397_vemc_3v3_reg>;
vqmmc-supply = <&mt6397_vio18_reg>;
clocks = <&pericfg CLK_PERI_MSDC30_0>,
<&topckgen CLK_TOP_MSDC50_0_H_SEL>;
clock-names = "source", "hclk";
pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&mmc0_pins_default>;
pinctrl-1 = <&mmc0_pins_uhs>;
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
hs400-ds-delay = <0x14015>;
mediatek,hs200-cmd-int-delay = <26>;
mediatek,hs400-cmd-int-delay = <14>;
mediatek,hs400-cmd-resp-sel-rising;
};

View file

@ -0,0 +1,176 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/mtk-sd.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MTK MSDC Storage Host Controller Binding
maintainers:
- Chaotian Jing <chaotian.jing@mediatek.com>
- Wenbin Mei <wenbin.mei@mediatek.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
oneOf:
- enum:
- mediatek,mt2701-mmc
- mediatek,mt2712-mmc
- mediatek,mt6779-mmc
- mediatek,mt7620-mmc
- mediatek,mt7622-mmc
- mediatek,mt8135-mmc
- mediatek,mt8173-mmc
- mediatek,mt8183-mmc
- mediatek,mt8516-mmc
- items:
- const: mediatek,mt7623-mmc
- const: mediatek,mt2701-mmc
- items:
- const: mediatek,mt8192-mmc
- const: mediatek,mt8183-mmc
clocks:
description:
Should contain phandle for the clock feeding the MMC controller.
minItems: 2
maxItems: 8
items:
- description: source clock (required).
- description: HCLK which used for host (required).
- description: independent source clock gate (required for MT2712).
- description: bus clock used for internal register access (required for MT2712 MSDC0/3).
- description: msdc subsys clock gate (required for MT8192).
- description: peripheral bus clock gate (required for MT8192).
- description: AXI bus clock gate (required for MT8192).
- description: AHB bus clock gate (required for MT8192).
clock-names:
minItems: 2
maxItems: 8
items:
- const: source
- const: hclk
- const: source_cg
- const: bus_clk
- const: sys_cg
- const: pclk_cg
- const: axi_cg
- const: ahb_cg
pinctrl-names:
items:
- const: default
- const: state_uhs
pinctrl-0:
description:
should contain default/high speed pin ctrl.
maxItems: 1
pinctrl-1:
description:
should contain uhs mode pin ctrl.
maxItems: 1
assigned-clocks:
description:
PLL of the source clock.
maxItems: 1
assigned-clock-parents:
description:
parent of source clock, used for HS400 mode to get 400Mhz source clock.
maxItems: 1
hs400-ds-delay:
$ref: /schemas/types.yaml#/definitions/uint32
description:
HS400 DS delay setting.
minimum: 0
maximum: 0xffffffff
mediatek,hs200-cmd-int-delay:
$ref: /schemas/types.yaml#/definitions/uint32
description:
HS200 command internal delay setting.
This field has total 32 stages.
The value is an integer from 0 to 31.
minimum: 0
maximum: 31
mediatek,hs400-cmd-int-delay:
$ref: /schemas/types.yaml#/definitions/uint32
description:
HS400 command internal delay setting.
This field has total 32 stages.
The value is an integer from 0 to 31.
minimum: 0
maximum: 31
mediatek,hs400-cmd-resp-sel-rising:
$ref: /schemas/types.yaml#/definitions/flag
description:
HS400 command response sample selection.
If present, HS400 command responses are sampled on rising edges.
If not present, HS400 command responses are sampled on falling edges.
mediatek,latch-ck:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Some SoCs do not support enhance_rx, need set correct latch-ck to avoid
data crc error caused by stop clock(fifo full) Valid range = [0:0x7].
if not present, default value is 0.
applied to compatible "mediatek,mt2701-mmc".
minimum: 0
maximum: 7
resets:
maxItems: 1
reset-names:
const: hrst
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- pinctrl-names
- pinctrl-0
- pinctrl-1
- vmmc-supply
- vqmmc-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/mt8173-clk.h>
mmc0: mmc@11230000 {
compatible = "mediatek,mt8173-mmc";
reg = <0x11230000 0x1000>;
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_LOW>;
vmmc-supply = <&mt6397_vemc_3v3_reg>;
vqmmc-supply = <&mt6397_vio18_reg>;
clocks = <&pericfg CLK_PERI_MSDC30_0>,
<&topckgen CLK_TOP_MSDC50_0_H_SEL>;
clock-names = "source", "hclk";
pinctrl-names = "default", "state_uhs";
pinctrl-0 = <&mmc0_pins_default>;
pinctrl-1 = <&mmc0_pins_uhs>;
assigned-clocks = <&topckgen CLK_TOP_MSDC50_0_SEL>;
assigned-clock-parents = <&topckgen CLK_TOP_MSDCPLL_D2>;
hs400-ds-delay = <0x14015>;
mediatek,hs200-cmd-int-delay = <26>;
mediatek,hs400-cmd-int-delay = <14>;
mediatek,hs400-cmd-resp-sel-rising;
};
...

View file

@ -17,7 +17,9 @@ properties:
oneOf:
- const: actions,owl-mmc
- items:
- const: actions,s700-mmc
- enum:
- actions,s500-mmc
- actions,s700-mmc
- const: actions,owl-mmc
reg:

View file

@ -468,7 +468,6 @@ static void memstick_check(struct work_struct *work)
host->card = card;
if (device_register(&card->dev)) {
put_device(&card->dev);
kfree(host->card);
host->card = NULL;
}
} else

View file

@ -276,7 +276,7 @@ static const char *mspro_block_attr_name(unsigned char tag)
return "attr_devinfo";
default:
return NULL;
};
}
}
typedef ssize_t (*sysfs_show_t)(struct device *dev,

View file

@ -748,7 +748,7 @@ static int jmb38x_ms_set_param(struct memstick_host *msh,
clock_delay);
host->ifmode = value;
break;
};
}
return 0;
}

View file

@ -759,8 +759,10 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto error3;
dev->mmio = pci_ioremap_bar(pdev, 0);
if (!dev->mmio)
if (!dev->mmio) {
error = -ENOMEM;
goto error4;
}
dev->irq = pdev->irq;
spin_lock_init(&dev->irq_lock);
@ -786,12 +788,14 @@ static int r592_probe(struct pci_dev *pdev, const struct pci_device_id *id)
&dev->dummy_dma_page_physical_address, GFP_KERNEL);
r592_stop_dma(dev , 0);
if (request_irq(dev->irq, &r592_irq, IRQF_SHARED,
DRV_NAME, dev))
error = request_irq(dev->irq, &r592_irq, IRQF_SHARED,
DRV_NAME, dev);
if (error)
goto error6;
r592_update_card_detect(dev);
if (memstick_add_host(host))
error = memstick_add_host(host);
if (error)
goto error7;
message("driver successfully loaded");

View file

@ -528,7 +528,7 @@ static int tifm_ms_set_param(struct memstick_host *msh,
} else
return -EINVAL;
break;
};
}
return 0;
}

View file

@ -26,16 +26,16 @@ static u8 rts5261_get_ic_version(struct rtsx_pcr *pcr)
static void rts5261_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
{
u8 driving_3v3[4][3] = {
{0x13, 0x13, 0x13},
{0x96, 0x96, 0x96},
{0x96, 0x96, 0x96},
{0x7F, 0x7F, 0x7F},
{0x96, 0x96, 0x96},
{0x13, 0x13, 0x13},
};
u8 driving_1v8[4][3] = {
{0x99, 0x99, 0x99},
{0xB3, 0xB3, 0xB3},
{0x3A, 0x3A, 0x3A},
{0xE6, 0xE6, 0xE6},
{0xB3, 0xB3, 0xB3},
{0x99, 0x99, 0x99},
};
u8 (*driving)[3], drive_sel;
@ -67,12 +67,17 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
if (!rts5261_vendor_setting_valid(reg)) {
/* Not support MMC default */
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
pcr_dbg(pcr, "skip fetch vendor setting\n");
return;
}
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rts5261_reg_to_card_drive_sel(reg);
if (!rts5261_reg_check_mmc_support(reg))
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
/* TO do: need to add rtd3 function */
pcr->rtd3_en = rts5261_reg_to_rtd3(reg);
if (rts5261_reg_check_reverse_socket(reg))
pcr->flags |= PCR_REVERSE_SOCKET;
@ -171,6 +176,8 @@ static int rts5261_card_power_on(struct rtsx_pcr *pcr, int card)
if (option->ocp_en)
rtsx_pci_enable_ocp(pcr);
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG1,
RTS5261_LDO1_TUNE_MASK, RTS5261_LDO1_33);
@ -272,6 +279,9 @@ static void rts5261_enable_ocp(struct rtsx_pcr *pcr)
u8 val = 0;
val = SD_OCP_INT_EN | SD_DETECT_EN;
rtsx_pci_write_register(pcr, RTS5261_LDO1_CFG0,
RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN,
RTS5261_LDO1_OCP_EN | RTS5261_LDO1_OCP_LMT_EN);
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
}
@ -295,6 +305,8 @@ static int rts5261_card_power_off(struct rtsx_pcr *pcr, int card)
err = rtsx_pci_write_register(pcr, RTS5261_LDO1233318_POW_CTL,
RTS5261_LDO_POWERON_MASK, 0);
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
CFG_SD_POW_AUTO_PD, 0);
if (pcr->option.ocp_en)
rtsx_pci_disable_ocp(pcr);
@ -340,7 +352,7 @@ static void rts5261_clear_ocpstat(struct rtsx_pcr *pcr)
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
udelay(10);
udelay(1000);
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
}
@ -353,9 +365,9 @@ static void rts5261_process_ocp(struct rtsx_pcr *pcr)
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
if (pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
rts5261_clear_ocpstat(pcr);
rts5261_card_power_off(pcr, RTSX_SD_CARD);
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
rts5261_clear_ocpstat(pcr);
pcr->ocp_stat = 0;
}
@ -467,6 +479,7 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
u32 val;
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
@ -481,6 +494,10 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
if (is_version_higher_than(pcr, PID_5261, IC_VER_B)) {
val = rtsx_pci_readl(pcr, RTSX_DUM_REG);
rtsx_pci_writel(pcr, RTSX_DUM_REG, val | 0x1);
}
rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG4,
RTS5261_AUX_CLK_16M_EN, 0);
@ -502,6 +519,11 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
/* Configure driving */
rts5261_fill_driving(pcr, OUTPUT_3V3);
if (pcr->flags & PCR_REVERSE_SOCKET)
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
else
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
/*
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
* to drive low, and we forcibly request clock.
@ -513,6 +535,7 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
rtsx_pci_write_register(pcr, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL,
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
@ -526,22 +549,30 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
static void rts5261_enable_aspm(struct rtsx_pcr *pcr, bool enable)
{
u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
if (pcr->aspm_enabled == enable)
return;
val |= (pcr->aspm_en & 0x02);
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
pcr->aspm_enabled = enable;
}
static void rts5261_disable_aspm(struct rtsx_pcr *pcr, bool enable)
{
u8 val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
u8 mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
if (pcr->aspm_enabled == enable)
return;
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, 0);
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
udelay(10);
pcr->aspm_enabled = enable;
@ -618,7 +649,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
if (is_version(pcr, PID_5261, IC_VER_D)) {
if (is_version_higher_than(pcr, PID_5261, IC_VER_C)) {
clk_divider = SD_CLK_DIVIDE_256;
card_clock = 60000000;
} else {
@ -669,7 +700,7 @@ int rts5261_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
div++;
}
n = (n / 2);
n = (n / 2) - 1;
pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
ssc_depth = depth[ssc_depth];
@ -738,15 +769,19 @@ void rts5261_init_params(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
struct rtsx_hw_param *hw_param = &pcr->hw_param;
u8 val;
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
rtsx_pci_read_register(pcr, RTS5261_FW_STATUS, &val);
if (!(val & RTS5261_EXPRESS_LINK_FAIL_MASK))
pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
pcr->num_slots = 1;
pcr->ops = &rts5261_pcr_ops;
pcr->flags = 0;
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
pcr->sd30_drive_sel_1v8 = 0x00;
pcr->sd30_drive_sel_3v3 = 0x00;
pcr->aspm_en = ASPM_L1_EN;
pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 11);
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);

View file

@ -12,12 +12,13 @@
/*New add*/
#define rts5261_vendor_setting_valid(reg) ((reg) & 0x010000)
#define rts5261_reg_to_aspm(reg) (((reg) >> 28) ^ 0x03)
#define rts5261_reg_to_aspm(reg) \
(((~(reg) >> 28) & 0x02) | (((reg) >> 28) & 0x01))
#define rts5261_reg_check_reverse_socket(reg) ((reg) & 0x04)
#define rts5261_reg_to_card_drive_sel(reg) ((((reg) >> 6) & 0x01) << 6)
#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) ^ 0x03)
#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) ^ 0x03)
#define rts5261_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 22) & 0x03)
#define rts5261_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 16) & 0x03)
#define rts5261_reg_to_rtd3(reg) ((reg) & 0x08)
#define rts5261_reg_check_mmc_support(reg) ((reg) & 0x10)
#define RTS5261_AUTOLOAD_CFG0 0xFF7B
#define RTS5261_AUTOLOAD_CFG1 0xFF7C
@ -60,28 +61,6 @@
/* DMACTL 0xFE2C */
#define RTS5261_DMA_PACK_SIZE_MASK 0xF0
/* FW config info register */
#define RTS5261_FW_CFG_INFO0 0xFF50
#define RTS5261_FW_EXPRESS_TEST_MASK (0x01<<0)
#define RTS5261_FW_EA_MODE_MASK (0x01<<5)
/* FW config register */
#define RTS5261_FW_CFG0 0xFF54
#define RTS5261_FW_ENTER_EXPRESS (0x01<<0)
#define RTS5261_FW_CFG1 0xFF55
#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01<<7)
#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01<<6)
#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01<<5)
/*MCU_bus_mode_sel: 0=real 8051 1=fake mcu*/
#define RTS5261_MCU_BUS_SEL_MASK (0x01<<4)
/*MCU_clock_sel:VerA 00=aux16M 01=aux400K 1x=REFCLK100M*/
/*MCU_clock_sel:VerB 00=aux400K 01=aux16M 10=REFCLK100M*/
#define RTS5261_MCU_CLOCK_SEL_MASK (0x03<<2)
#define RTS5261_MCU_CLOCK_SEL_16M (0x01<<2)
#define RTS5261_MCU_CLOCK_GATING (0x01<<1)
#define RTS5261_DRIVER_ENABLE_FW (0x01<<0)
/* FW status register */
#define RTS5261_FW_STATUS 0xFF56
#define RTS5261_EXPRESS_LINK_FAIL_MASK (0x01<<7)
@ -121,12 +100,6 @@
#define RTS5261_DV3318_19 (0x04<<4)
#define RTS5261_DV3318_33 (0x07<<4)
#define RTS5261_LDO1_CFG0 0xFF72
#define RTS5261_LDO1_OCP_THD_MASK (0x07<<5)
#define RTS5261_LDO1_OCP_EN (0x01<<4)
#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03<<2)
#define RTS5261_LDO1_OCP_LMT_EN (0x01<<1)
/* CRD6603-433 190319 request changed */
#define RTS5261_LDO1_OCP_THD_740 (0x00<<5)
#define RTS5261_LDO1_OCP_THD_800 (0x01<<5)

View file

@ -1004,6 +1004,11 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
} else {
pcr->card_removed |= SD_EXIST;
pcr->card_inserted &= ~SD_EXIST;
if (PCI_PID(pcr) == PID_5261) {
rtsx_pci_write_register(pcr, RTS5261_FW_STATUS,
RTS5261_EXPRESS_LINK_FAIL_MASK, 0);
pcr->extra_caps |= EXTRA_CAPS_SD_EXPRESS;
}
}
pcr->dma_error_count = 0;
}

View file

@ -2147,8 +2147,12 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
mmc_go_idle(host);
if (!(host->caps2 & MMC_CAP2_NO_SD))
mmc_send_if_cond(host, host->ocr_avail);
if (!(host->caps2 & MMC_CAP2_NO_SD)) {
if (mmc_send_if_cond_pcie(host, host->ocr_avail))
goto out;
if (mmc_card_sd_express(host))
return 0;
}
/* Order's important: probe SDIO, then SD, then MMC */
if (!(host->caps2 & MMC_CAP2_NO_SDIO))
@ -2163,6 +2167,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
if (!mmc_attach_mmc(host))
return 0;
out:
mmc_power_off(host);
return -EIO;
}
@ -2290,6 +2295,12 @@ void mmc_rescan(struct work_struct *work)
goto out;
}
/* If an SD express card is present, then leave it as is. */
if (mmc_card_sd_express(host)) {
mmc_release_host(host);
goto out;
}
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int freq = freqs[i];
if (freq > host->f_max) {

View file

@ -77,5 +77,11 @@ static inline bool mmc_card_hs400es(struct mmc_card *card)
return card->host->ios.enhanced_strobe;
}
static inline bool mmc_card_sd_express(struct mmc_host *host)
{
return host->ios.timing == MMC_TIMING_SD_EXP ||
host->ios.timing == MMC_TIMING_SD_EXP_1_2V;
}
#endif

View file

@ -158,7 +158,8 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
return err;
}
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
static int __mmc_send_if_cond(struct mmc_host *host, u32 ocr, u8 pcie_bits,
u32 *resp)
{
struct mmc_command cmd = {};
int err;
@ -171,7 +172,7 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
* SD 1.0 cards.
*/
cmd.opcode = SD_SEND_IF_COND;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | pcie_bits << 8 | test_pattern;
cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, 0);
@ -186,6 +187,50 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
if (result_pattern != test_pattern)
return -EIO;
if (resp)
*resp = cmd.resp[0];
return 0;
}
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{
return __mmc_send_if_cond(host, ocr, 0, NULL);
}
int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr)
{
u32 resp = 0;
u8 pcie_bits = 0;
int ret;
if (host->caps2 & MMC_CAP2_SD_EXP) {
/* Probe card for SD express support via PCIe. */
pcie_bits = 0x10;
if (host->caps2 & MMC_CAP2_SD_EXP_1_2V)
/* Probe also for 1.2V support. */
pcie_bits = 0x30;
}
ret = __mmc_send_if_cond(host, ocr, pcie_bits, &resp);
if (ret)
return 0;
/* Continue with the SD express init, if the card supports it. */
resp &= 0x3000;
if (pcie_bits && resp) {
if (resp == 0x3000)
host->ios.timing = MMC_TIMING_SD_EXP_1_2V;
else
host->ios.timing = MMC_TIMING_SD_EXP;
/*
* According to the spec the clock shall also be gated, but
* let's leave this to the host driver for more flexibility.
*/
return host->ops->init_sd_express(host, &host->ios);
}
return 0;
}

View file

@ -16,6 +16,7 @@ struct mmc_host;
int mmc_app_set_bus_width(struct mmc_card *card, int width);
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
int mmc_send_if_cond_pcie(struct mmc_host *host, u32 ocr);
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca);
int mmc_app_send_scr(struct mmc_card *card);
int mmc_sd_switch(struct mmc_card *card, int mode, int group,

View file

@ -631,8 +631,8 @@ config MMC_SPI
config MMC_S3C
tristate "Samsung S3C SD/MMC Card Interface support"
depends on ARCH_S3C24XX
depends on S3C24XX_DMAC
depends on ARCH_S3C24XX || COMPILE_TEST
depends on S3C24XX_DMAC || COMPILE_TEST
help
This selects a driver for the MCI interface found in
Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs.
@ -664,7 +664,7 @@ config MMC_S3C_PIO
config MMC_S3C_DMA
bool "Use DMA transfers only"
help
Use DMA to transfer data between memory and the hardare.
Use DMA to transfer data between memory and the hardware.
Currently, the DMA support in this driver seems to not be
working properly and needs to be debugged before this
@ -1023,6 +1023,7 @@ config MMC_BCM2835
config MMC_MTK
tristate "MediaTek SD/MMC Card Interface support"
depends on HAS_DMA
depends on COMMON_CLK
select REGULATOR
select MMC_CQHCI
help

View file

@ -290,7 +290,7 @@ static void mmc_davinci_start_command(struct mmc_davinci_host *host,
default:
s = ", (R? response)";
break;
}; s; }));
} s; }));
host->cmd = cmd;
switch (mmc_resp_type(cmd)) {

View file

@ -2617,7 +2617,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
struct dw_mci *host = dev_id;
u32 pending;
struct dw_mci_slot *slot = host->slot;
unsigned long irqflags;
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
@ -2632,15 +2631,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
* Hold the lock; we know cmd11_timer can't be kicked
* off after the lock is released, so safe to delete.
*/
spin_lock_irqsave(&host->irq_lock, irqflags);
spin_lock(&host->irq_lock);
dw_mci_cmd_interrupt(host, pending);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
spin_unlock(&host->irq_lock);
del_timer(&host->cmd11_timer);
}
if (pending & DW_MCI_CMD_ERROR_FLAGS) {
spin_lock_irqsave(&host->irq_lock, irqflags);
spin_lock(&host->irq_lock);
del_timer(&host->cto_timer);
mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
@ -2648,7 +2647,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
smp_wmb(); /* drain writebuffer */
set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
spin_unlock(&host->irq_lock);
}
if (pending & DW_MCI_DATA_ERROR_FLAGS) {
@ -2661,7 +2660,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_DATA_OVER) {
spin_lock_irqsave(&host->irq_lock, irqflags);
spin_lock(&host->irq_lock);
del_timer(&host->dto_timer);
@ -2676,7 +2675,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
set_bit(EVENT_DATA_COMPLETE, &host->pending_events);
tasklet_schedule(&host->tasklet);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
spin_unlock(&host->irq_lock);
}
if (pending & SDMMC_INT_RXDR) {
@ -2692,12 +2691,12 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
}
if (pending & SDMMC_INT_CMD_DONE) {
spin_lock_irqsave(&host->irq_lock, irqflags);
spin_lock(&host->irq_lock);
mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
dw_mci_cmd_interrupt(host, pending);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
spin_unlock(&host->irq_lock);
}
if (pending & SDMMC_INT_CD) {

View file

@ -1265,7 +1265,7 @@ static struct platform_driver meson_mmc_driver = {
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(meson_mmc_of_match),
.of_match_table = meson_mmc_of_match,
},
};

View file

@ -418,10 +418,9 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
{
struct meson_mx_mmc_host *host = (void *) data;
u32 irqs, send;
unsigned long irqflags;
irqreturn_t ret;
spin_lock_irqsave(&host->irq_lock, irqflags);
spin_lock(&host->irq_lock);
irqs = readl(host->base + MESON_MX_SDIO_IRQS);
send = readl(host->base + MESON_MX_SDIO_SEND);
@ -434,7 +433,7 @@ static irqreturn_t meson_mx_mmc_irq(int irq, void *data)
/* finally ACK all pending interrupts */
writel(irqs, host->base + MESON_MX_SDIO_IRQS);
spin_unlock_irqrestore(&host->irq_lock, irqflags);
spin_unlock(&host->irq_lock);
return ret;
}

View file

@ -465,9 +465,8 @@ static irqreturn_t moxart_irq(int irq, void *devid)
{
struct moxart_host *host = (struct moxart_host *)devid;
u32 status;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
spin_lock(&host->lock);
status = readl(host->base + REG_STATUS);
if (status & CARD_CHANGE) {
@ -484,7 +483,7 @@ static irqreturn_t moxart_irq(int irq, void *devid)
if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq)
moxart_transfer_pio(host);
spin_unlock_irqrestore(&host->lock, flags);
spin_unlock(&host->lock);
return IRQ_HANDLED;
}

View file

@ -35,6 +35,7 @@
#include "cqhci.h"
#define MAX_BD_NUM 1024
#define MSDC_NR_CLOCKS 3
/*--------------------------------------------------------------------------*/
/* Common Definition */
@ -77,9 +78,12 @@
#define MSDC_PAD_TUNE0 0xf0
#define PAD_DS_TUNE 0x188
#define PAD_CMD_TUNE 0x18c
#define EMMC51_CFG0 0x204
#define EMMC50_CFG0 0x208
#define EMMC50_CFG1 0x20c
#define EMMC50_CFG3 0x220
#define SDC_FIFO_CFG 0x228
#define CQHCI_SETTING 0x7fc
/*--------------------------------------------------------------------------*/
/* Top Pad Register Offset */
@ -260,15 +264,26 @@
#define PAD_CMD_TUNE_RX_DLY3 (0x1f << 1) /* RW */
/* EMMC51_CFG0 mask */
#define CMDQ_RDAT_CNT (0x3ff << 12) /* RW */
#define EMMC50_CFG_PADCMD_LATCHCK (0x1 << 0) /* RW */
#define EMMC50_CFG_CRCSTS_EDGE (0x1 << 3) /* RW */
#define EMMC50_CFG_CFCSTS_SEL (0x1 << 4) /* RW */
#define EMMC50_CFG_CMD_RESP_SEL (0x1 << 9) /* RW */
/* EMMC50_CFG1 mask */
#define EMMC50_CFG1_DS_CFG (0x1 << 28) /* RW */
#define EMMC50_CFG3_OUTS_WR (0x1f << 0) /* RW */
#define SDC_FIFO_CFG_WRVALIDSEL (0x1 << 24) /* RW */
#define SDC_FIFO_CFG_RDVALIDSEL (0x1 << 25) /* RW */
/* CQHCI_SETTING */
#define CQHCI_RD_CMD_WND_SEL (0x1 << 14) /* RW */
#define CQHCI_WR_CMD_WND_SEL (0x1 << 15) /* RW */
/* EMMC_TOP_CONTROL mask */
#define PAD_RXDLY_SEL (0x1 << 0) /* RW */
#define DELAY_EN (0x1 << 1) /* RW */
@ -425,6 +440,8 @@ struct msdc_host {
struct clk *h_clk; /* msdc h_clk */
struct clk *bus_clk; /* bus clock which used to access register */
struct clk *src_clk_cg; /* msdc source clock control gate */
struct clk *sys_clk_cg; /* msdc subsys clock control gate */
struct clk_bulk_data bulk_clks[MSDC_NR_CLOCKS];
u32 mclk; /* mmc subsystem clock frequency */
u32 src_clk_freq; /* source clock frequency */
unsigned char timing;
@ -785,6 +802,7 @@ static void msdc_set_busy_timeout(struct msdc_host *host, u64 ns, u64 clks)
static void msdc_gate_clock(struct msdc_host *host)
{
clk_bulk_disable_unprepare(MSDC_NR_CLOCKS, host->bulk_clks);
clk_disable_unprepare(host->src_clk_cg);
clk_disable_unprepare(host->src_clk);
clk_disable_unprepare(host->bus_clk);
@ -793,10 +811,18 @@ static void msdc_gate_clock(struct msdc_host *host)
static void msdc_ungate_clock(struct msdc_host *host)
{
int ret;
clk_prepare_enable(host->h_clk);
clk_prepare_enable(host->bus_clk);
clk_prepare_enable(host->src_clk);
clk_prepare_enable(host->src_clk_cg);
ret = clk_bulk_prepare_enable(MSDC_NR_CLOCKS, host->bulk_clks);
if (ret) {
dev_err(host->dev, "Cannot enable pclk/axi/ahb clock gates\n");
return;
}
while (!(readl(host->base + MSDC_CFG) & MSDC_CFG_CKSTB))
cpu_relax();
}
@ -1537,13 +1563,12 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
struct mmc_host *mmc = mmc_from_priv(host);
while (true) {
unsigned long flags;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
u32 events, event_mask;
spin_lock_irqsave(&host->lock, flags);
spin_lock(&host->lock);
events = readl(host->base + MSDC_INT);
event_mask = readl(host->base + MSDC_INTEN);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
@ -1554,7 +1579,7 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
mrq = host->mrq;
cmd = host->cmd;
data = host->data;
spin_unlock_irqrestore(&host->lock, flags);
spin_unlock(&host->lock);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
sdio_signal_irq(mmc);
@ -2266,6 +2291,31 @@ static int msdc_get_cd(struct mmc_host *mmc)
return !val;
}
static void msdc_hs400_enhanced_strobe(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct msdc_host *host = mmc_priv(mmc);
if (ios->enhanced_strobe) {
msdc_prepare_hs400_tuning(mmc, ios);
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 1);
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 1);
sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 1);
sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
sdr_clr_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
sdr_clr_bits(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT);
} else {
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_PADCMD_LATCHCK, 0);
sdr_set_field(host->base + EMMC50_CFG0, EMMC50_CFG_CMD_RESP_SEL, 0);
sdr_set_field(host->base + EMMC50_CFG1, EMMC50_CFG1_DS_CFG, 0);
sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_RD_CMD_WND_SEL);
sdr_set_bits(host->base + CQHCI_SETTING, CQHCI_WR_CMD_WND_SEL);
sdr_set_field(host->base + EMMC51_CFG0, CMDQ_RDAT_CNT, 0xb4);
}
}
static void msdc_cqe_enable(struct mmc_host *mmc)
{
struct msdc_host *host = mmc_priv(mmc);
@ -2323,6 +2373,7 @@ static const struct mmc_host_ops mt_msdc_ops = {
.set_ios = msdc_ops_set_ios,
.get_ro = mmc_gpio_get_ro,
.get_cd = msdc_get_cd,
.hs400_enhanced_strobe = msdc_hs400_enhanced_strobe,
.enable_sdio_irq = msdc_enable_sdio_irq,
.ack_sdio_irq = msdc_ack_sdio_irq,
.start_signal_voltage_switch = msdc_ops_switch_volt,
@ -2367,6 +2418,48 @@ static void msdc_of_property_parse(struct platform_device *pdev,
host->cqhci = false;
}
static int msdc_of_clock_parse(struct platform_device *pdev,
struct msdc_host *host)
{
int ret;
host->src_clk = devm_clk_get(&pdev->dev, "source");
if (IS_ERR(host->src_clk))
return PTR_ERR(host->src_clk);
host->h_clk = devm_clk_get(&pdev->dev, "hclk");
if (IS_ERR(host->h_clk))
return PTR_ERR(host->h_clk);
host->bus_clk = devm_clk_get_optional(&pdev->dev, "bus_clk");
if (IS_ERR(host->bus_clk))
host->bus_clk = NULL;
/*source clock control gate is optional clock*/
host->src_clk_cg = devm_clk_get_optional(&pdev->dev, "source_cg");
if (IS_ERR(host->src_clk_cg))
host->src_clk_cg = NULL;
host->sys_clk_cg = devm_clk_get_optional(&pdev->dev, "sys_cg");
if (IS_ERR(host->sys_clk_cg))
host->sys_clk_cg = NULL;
/* If present, always enable for this clock gate */
clk_prepare_enable(host->sys_clk_cg);
host->bulk_clks[0].id = "pclk_cg";
host->bulk_clks[1].id = "axi_cg";
host->bulk_clks[2].id = "ahb_cg";
ret = devm_clk_bulk_get_optional(&pdev->dev, MSDC_NR_CLOCKS,
host->bulk_clks);
if (ret) {
dev_err(&pdev->dev, "Cannot get pclk/axi/ahb clock gates\n");
return ret;
}
return 0;
}
static int msdc_drv_probe(struct platform_device *pdev)
{
struct mmc_host *mmc;
@ -2406,30 +2499,16 @@ static int msdc_drv_probe(struct platform_device *pdev)
if (ret)
goto host_free;
host->src_clk = devm_clk_get(&pdev->dev, "source");
if (IS_ERR(host->src_clk)) {
ret = PTR_ERR(host->src_clk);
ret = msdc_of_clock_parse(pdev, host);
if (ret)
goto host_free;
}
host->h_clk = devm_clk_get(&pdev->dev, "hclk");
if (IS_ERR(host->h_clk)) {
ret = PTR_ERR(host->h_clk);
goto host_free;
}
host->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
if (IS_ERR(host->bus_clk))
host->bus_clk = NULL;
/*source clock control gate is optional clock*/
host->src_clk_cg = devm_clk_get(&pdev->dev, "source_cg");
if (IS_ERR(host->src_clk_cg))
host->src_clk_cg = NULL;
host->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
"hrst");
if (IS_ERR(host->reset))
return PTR_ERR(host->reset);
if (IS_ERR(host->reset)) {
ret = PTR_ERR(host->reset);
goto host_free;
}
host->irq = platform_get_irq(pdev, 0);
if (host->irq < 0) {

View file

@ -157,32 +157,16 @@ struct mxcmci_host {
enum mxcmci_type devtype;
};
static const struct platform_device_id mxcmci_devtype[] = {
{
.name = "imx21-mmc",
.driver_data = IMX21_MMC,
}, {
.name = "imx31-mmc",
.driver_data = IMX31_MMC,
}, {
.name = "mpc512x-sdhc",
.driver_data = MPC512X_MMC,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, mxcmci_devtype);
static const struct of_device_id mxcmci_of_match[] = {
{
.compatible = "fsl,imx21-mmc",
.data = &mxcmci_devtype[IMX21_MMC],
.data = (void *) IMX21_MMC,
}, {
.compatible = "fsl,imx31-mmc",
.data = &mxcmci_devtype[IMX31_MMC],
.data = (void *) IMX31_MMC,
}, {
.compatible = "fsl,mpc5121-sdhc",
.data = &mxcmci_devtype[MPC512X_MMC],
.data = (void *) MPC512X_MMC,
}, {
/* sentinel */
}
@ -1001,13 +985,10 @@ static int mxcmci_probe(struct platform_device *pdev)
int ret = 0, irq;
bool dat3_card_detect = false;
dma_cap_mask_t mask;
const struct of_device_id *of_id;
struct imxmmc_platform_data *pdata = pdev->dev.platform_data;
pr_info("i.MX/MPC512x SDHC driver\n");
of_id = of_match_device(mxcmci_of_match, &pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@ -1044,12 +1025,7 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size;
if (of_id) {
const struct platform_device_id *id_entry = of_id->data;
host->devtype = id_entry->driver_data;
} else {
host->devtype = pdev->id_entry->driver_data;
}
host->devtype = (enum mxcmci_type)of_device_get_match_data(&pdev->dev);
/* adjust max_segs after devtype detection */
if (!is_mpc512x_mmc(host))
@ -1241,7 +1217,6 @@ static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe,
.remove = mxcmci_remove,
.id_table = mxcmci_devtype,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,

View file

@ -545,19 +545,6 @@ static const struct mmc_host_ops mxs_mmc_ops = {
.enable_sdio_irq = mxs_mmc_enable_sdio_irq,
};
static const struct platform_device_id mxs_ssp_ids[] = {
{
.name = "imx23-mmc",
.driver_data = IMX23_SSP,
}, {
.name = "imx28-mmc",
.driver_data = IMX28_SSP,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, mxs_ssp_ids);
static const struct of_device_id mxs_mmc_dt_ids[] = {
{ .compatible = "fsl,imx23-mmc", .data = (void *) IMX23_SSP, },
{ .compatible = "fsl,imx28-mmc", .data = (void *) IMX28_SSP, },
@ -567,8 +554,6 @@ MODULE_DEVICE_TABLE(of, mxs_mmc_dt_ids);
static int mxs_mmc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_mmc_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host;
struct mmc_host *mmc;
@ -593,7 +578,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
goto out_mmc_free;
}
ssp->devid = (enum mxs_ssp_id) of_id->data;
ssp->devid = (enum mxs_ssp_id)of_device_get_match_data(&pdev->dev);
host->mmc = mmc;
host->sdio_irq_en = 0;
@ -723,7 +708,6 @@ static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe,
.remove = mxs_mmc_remove,
.id_table = mxs_ssp_ids,
.driver = {
.name = DRIVER_NAME,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,

View file

@ -134,10 +134,9 @@ static void owl_mmc_update_reg(void __iomem *reg, unsigned int val, bool state)
static irqreturn_t owl_irq_handler(int irq, void *devid)
{
struct owl_mmc_host *owl_host = devid;
unsigned long flags;
u32 state;
spin_lock_irqsave(&owl_host->lock, flags);
spin_lock(&owl_host->lock);
state = readl(owl_host->base + OWL_REG_SD_STATE);
if (state & OWL_SD_STATE_TEI) {
@ -147,7 +146,7 @@ static irqreturn_t owl_irq_handler(int irq, void *devid)
complete(&owl_host->sdc_complete);
}
spin_unlock_irqrestore(&owl_host->lock, flags);
spin_unlock(&owl_host->lock);
return IRQ_HANDLED;
}
@ -522,11 +521,11 @@ static void owl_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Enable DDR mode if requested */
if (ios->timing == MMC_TIMING_UHS_DDR50) {
owl_host->ddr_50 = 1;
owl_host->ddr_50 = true;
owl_mmc_update_reg(owl_host->base + OWL_REG_SD_EN,
OWL_SD_EN_DDREN, true);
} else {
owl_host->ddr_50 = 0;
owl_host->ddr_50 = false;
}
}

View file

@ -731,6 +731,7 @@ static int pxamci_probe(struct platform_device *pdev)
host->power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW);
if (IS_ERR(host->power)) {
ret = PTR_ERR(host->power);
dev_err(dev, "Failed requesting gpio_power\n");
goto out;
}

View file

@ -18,28 +18,39 @@
*
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/mfd/tmio.h>
#include <linux/sh_dma.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#include "renesas_sdhi.h"
#include "tmio_mmc.h"
#define HOST_MODE 0xe4
#define CTL_HOST_MODE 0xe4
#define HOST_MODE_GEN2_SDR50_WMODE BIT(0)
#define HOST_MODE_GEN2_SDR104_WMODE BIT(0)
#define HOST_MODE_GEN3_WMODE BIT(0)
#define HOST_MODE_GEN3_BUSWIDTH BIT(8)
#define HOST_MODE_GEN3_16BIT HOST_MODE_GEN3_WMODE
#define HOST_MODE_GEN3_32BIT (HOST_MODE_GEN3_WMODE | HOST_MODE_GEN3_BUSWIDTH)
#define HOST_MODE_GEN3_64BIT 0
#define CTL_SDIF_MODE 0xe6
#define SDIF_MODE_HS400 BIT(0)
#define SDHI_VER_GEN2_SDR50 0x490c
#define SDHI_VER_RZ_A1 0x820b
@ -60,26 +71,26 @@ static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
*/
switch (sd_ctrl_read16(host, CTL_VERSION)) {
case SDHI_VER_GEN2_SDR50:
val = (width == 32) ? 0x0001 : 0x0000;
val = (width == 32) ? HOST_MODE_GEN2_SDR50_WMODE : 0;
break;
case SDHI_VER_GEN2_SDR104:
val = (width == 32) ? 0x0000 : 0x0001;
val = (width == 32) ? 0 : HOST_MODE_GEN2_SDR104_WMODE;
break;
case SDHI_VER_GEN3_SD:
case SDHI_VER_GEN3_SDMMC:
if (width == 64)
val = 0x0000;
val = HOST_MODE_GEN3_64BIT;
else if (width == 32)
val = 0x0101;
val = HOST_MODE_GEN3_32BIT;
else
val = 0x0001;
val = HOST_MODE_GEN3_16BIT;
break;
default:
/* nothing to do */
return;
}
sd_ctrl_write16(host, HOST_MODE, val);
sd_ctrl_write16(host, CTL_HOST_MODE, val);
}
static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
@ -373,7 +384,7 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
/* Set HS400 mode */
sd_ctrl_write16(host, CTL_SDIF_MODE, 0x0001 |
sd_ctrl_write16(host, CTL_SDIF_MODE, SDIF_MODE_HS400 |
sd_ctrl_read16(host, CTL_SDIF_MODE));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF,
@ -424,9 +435,11 @@ static void renesas_sdhi_hs400_complete(struct mmc_host *mmc)
priv->needs_adjust_hs400 = true;
}
static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
struct renesas_sdhi *priv)
static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host);
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
@ -434,14 +447,6 @@ static void renesas_sdhi_reset_scc(struct tmio_mmc_host *host,
~SH_MOBILE_SDHI_SCC_CKSEL_DTSEL &
sd_scc_read32(host, priv,
SH_MOBILE_SDHI_SCC_CKSEL));
}
static void renesas_sdhi_disable_scc(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
struct renesas_sdhi *priv = host_to_priv(host);
renesas_sdhi_reset_scc(host, priv);
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DTCNTL,
~SH_MOBILE_SDHI_SCC_DTCNTL_TAPEN &
@ -527,7 +532,7 @@ static void renesas_sdhi_reset_hs400_mode(struct tmio_mmc_host *host,
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
/* Reset HS400 mode */
sd_ctrl_write16(host, CTL_SDIF_MODE, ~0x0001 &
sd_ctrl_write16(host, CTL_SDIF_MODE, ~SDIF_MODE_HS400 &
sd_ctrl_read16(host, CTL_SDIF_MODE));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_DT2FF, priv->scc_tappos);
@ -552,24 +557,38 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
return 0;
}
/* only populated for TMIO_MMC_MIN_RCAR2 */
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
u16 val;
renesas_sdhi_reset_scc(host, priv);
renesas_sdhi_reset_hs400_mode(host, priv);
priv->needs_adjust_hs400 = false;
if (priv->scc_ctl) {
renesas_sdhi_disable_scc(host->mmc);
renesas_sdhi_reset_hs400_mode(host, priv);
priv->needs_adjust_hs400 = false;
sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
}
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_INIT_RCAR2);
if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
val |= CARD_OPT_EXTOP;
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, val);
}
}
static unsigned int renesas_sdhi_gen3_get_cycles(struct tmio_mmc_host *host)
{
u16 num, val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
num = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
return 1 << ((val & CARD_OPT_EXTOP ? 14 : 13) + num);
if (host->pdata->flags & TMIO_MMC_MIN_RCAR2)
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK,
TMIO_MASK_INIT_RCAR2);
}
#define SH_MOBILE_SDHI_MIN_TAP_ROW 3
@ -803,7 +822,7 @@ static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
case CTL_SD_MEM_CARD_OPT:
case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE:
case HOST_MODE:
case CTL_HOST_MODE:
if (host->pdata->flags & TMIO_MMC_HAVE_CBSY)
bit = TMIO_STAT_CMD_BUSY;
fallthrough;
@ -1005,11 +1024,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.start_signal_voltage_switch =
renesas_sdhi_start_signal_voltage_switch;
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
if (of_data && of_data->scc_offset) {
priv->scc_ctl = host->ctl + of_data->scc_offset;
host->reset = renesas_sdhi_reset;
}
host->reset = renesas_sdhi_reset;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@ -1042,6 +1057,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
/* All SDHI support HW busy detection */
mmc_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
dev_pm_domain_start(&pdev->dev);
ret = renesas_sdhi_clk_enable(host);
@ -1065,9 +1083,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
quirks->hs400_calib_table + 1);
}
ret = tmio_mmc_host_probe(host);
if (ret < 0)
goto edisclk;
/* these have an EXTOP bit */
if (ver >= SDHI_VER_GEN3_SD)
host->get_timeout_cycles = renesas_sdhi_gen3_get_cycles;
/* Enable tuning iff we have an SCC and a supported mode */
if (of_data && of_data->scc_offset &&
@ -1093,6 +1111,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (!hit)
dev_warn(&host->pdev->dev, "Unknown clock rate for tuning\n");
priv->scc_ctl = host->ctl + of_data->scc_offset;
host->check_retune = renesas_sdhi_check_scc_error;
host->ops.execute_tuning = renesas_sdhi_execute_tuning;
host->ops.prepare_hs400_tuning = renesas_sdhi_prepare_hs400_tuning;
@ -1100,6 +1119,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.hs400_complete = renesas_sdhi_hs400_complete;
}
ret = tmio_mmc_host_probe(host);
if (ret < 0)
goto edisclk;
num_irqs = platform_irq_count(pdev);
if (num_irqs < 0) {
ret = num_irqs;

View file

@ -48,6 +48,8 @@ struct realtek_pci_sdmmc {
bool using_cookie;
};
static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios);
static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
{
return &(host->pdev->dev);
@ -896,7 +898,10 @@ static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
static int sd_power_on(struct realtek_pci_sdmmc *host)
{
struct rtsx_pcr *pcr = host->pcr;
struct mmc_host *mmc = host->mmc;
int err;
u32 val;
u8 test_mode;
if (host->power_state == SDMMC_POWER_ON)
return 0;
@ -923,6 +928,30 @@ static int sd_power_on(struct realtek_pci_sdmmc *host)
if (err < 0)
return err;
if (PCI_PID(pcr) == PID_5261) {
/*
* If test mode is set switch to SD Express mandatorily,
* this is only for factory testing.
*/
rtsx_pci_read_register(pcr, RTS5261_FW_CFG_INFO0, &test_mode);
if (test_mode & RTS5261_FW_EXPRESS_TEST_MASK) {
sdmmc_init_sd_express(mmc, NULL);
return 0;
}
if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
/*
* HW read wp status when resuming from S3/S4,
* and then picks SD legacy interface if it's set
* in read-only mode.
*/
val = rtsx_pci_readl(pcr, RTSX_BIPR);
if (val & SD_WRITE_PROTECT) {
pcr->extra_caps &= ~EXTRA_CAPS_SD_EXPRESS;
mmc->caps2 &= ~(MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V);
}
}
host->power_state = SDMMC_POWER_ON;
return 0;
}
@ -1309,6 +1338,45 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
return err;
}
static int sdmmc_init_sd_express(struct mmc_host *mmc, struct mmc_ios *ios)
{
u32 relink_time;
struct realtek_pci_sdmmc *host = mmc_priv(mmc);
struct rtsx_pcr *pcr = host->pcr;
/* Set relink_time for changing to PCIe card */
relink_time = 0x8FFF;
rtsx_pci_write_register(pcr, 0xFF01, 0xFF, relink_time);
rtsx_pci_write_register(pcr, 0xFF02, 0xFF, relink_time >> 8);
rtsx_pci_write_register(pcr, 0xFF03, 0x01, relink_time >> 16);
rtsx_pci_write_register(pcr, PETXCFG, 0x80, 0x80);
rtsx_pci_write_register(pcr, LDO_VCC_CFG0,
RTS5261_LDO1_OCP_THD_MASK,
pcr->option.sd_800mA_ocp_thd);
if (pcr->ops->disable_auto_blink)
pcr->ops->disable_auto_blink(pcr);
/* For PCIe/NVMe mode can't enter delink issue */
pcr->hw_param.interrupt_en &= ~(SD_INT_EN);
rtsx_pci_writel(pcr, RTSX_BIER, pcr->hw_param.interrupt_en);
rtsx_pci_write_register(pcr, RTS5260_AUTOLOAD_CFG4,
RTS5261_AUX_CLK_16M_EN, RTS5261_AUX_CLK_16M_EN);
rtsx_pci_write_register(pcr, RTS5261_FW_CFG0,
RTS5261_FW_ENTER_EXPRESS, RTS5261_FW_ENTER_EXPRESS);
rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
RTS5261_MCU_CLOCK_GATING, RTS5261_MCU_CLOCK_GATING);
rtsx_pci_write_register(pcr, RTS5261_FW_CFG1,
RTS5261_MCU_BUS_SEL_MASK | RTS5261_MCU_CLOCK_SEL_MASK
| RTS5261_DRIVER_ENABLE_FW,
RTS5261_MCU_CLOCK_SEL_16M | RTS5261_DRIVER_ENABLE_FW);
host->eject = true;
return 0;
}
static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.pre_req = sdmmc_pre_req,
.post_req = sdmmc_post_req,
@ -1318,6 +1386,7 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.get_cd = sdmmc_get_cd,
.start_signal_voltage_switch = sdmmc_switch_voltage,
.execute_tuning = sdmmc_execute_tuning,
.init_sd_express = sdmmc_init_sd_express,
};
static void init_extra_caps(struct realtek_pci_sdmmc *host)
@ -1339,6 +1408,8 @@ static void init_extra_caps(struct realtek_pci_sdmmc *host)
mmc->caps |= MMC_CAP_8_BIT_DATA;
if (pcr->extra_caps & EXTRA_CAPS_NO_MMC)
mmc->caps2 |= MMC_CAP2_NO_MMC;
if (pcr->extra_caps & EXTRA_CAPS_SD_EXPRESS)
mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;
}
static void realtek_init_host(struct realtek_pci_sdmmc *host)

View file

@ -17,7 +17,7 @@
#include <linux/cpufreq.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>

View file

@ -5,6 +5,7 @@
* Copyright (c) 2012, Intel Corporation.
*/
#include <linux/bitfield.h>
#include <linux/init.h>
#include <linux/export.h>
#include <linux/module.h>
@ -545,10 +546,41 @@ struct amd_sdhci_host {
static int amd_select_drive_strength(struct mmc_card *card,
unsigned int max_dtr, int host_drv,
int card_drv, int *drv_type)
int card_drv, int *host_driver_strength)
{
*drv_type = MMC_SET_DRIVER_TYPE_A;
return MMC_SET_DRIVER_TYPE_A;
struct sdhci_host *host = mmc_priv(card->host);
u16 preset, preset_driver_strength;
/*
* This method is only called by mmc_select_hs200 so we only need to
* read from the HS200 (SDR104) preset register.
*
* Firmware that has "invalid/default" presets return a driver strength
* of A. This matches the previously hard coded value.
*/
preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
preset_driver_strength = FIELD_GET(SDHCI_PRESET_DRV_MASK, preset);
/*
* We want the controller driver strength to match the card's driver
* strength so they have similar rise/fall times.
*
* The controller driver strength set by this method is sticky for all
* timings after this method is called. This unfortunately means that
* while HS400 tuning is in progress we end up with mismatched driver
* strengths between the controller and the card. HS400 tuning requires
* switching from HS400->DDR52->HS->HS200->HS400. So the driver mismatch
* happens while in DDR52 and HS modes. This has not been observed to
* cause problems. Enabling presets would fix this issue.
*/
*host_driver_strength = preset_driver_strength;
/*
* The resulting card driver strength is only set when switching the
* card's timing to HS200 or HS400. The card will use the default driver
* strength (B) for any other mode.
*/
return preset_driver_strength;
}
static void sdhci_acpi_amd_hs400_dll(struct sdhci_host *host, bool enable)

View file

@ -296,22 +296,6 @@ struct pltfm_imx_data {
struct pm_qos_request pm_qos_req;
};
static const struct platform_device_id imx_esdhc_devtype[] = {
{
.name = "sdhci-esdhc-imx25",
.driver_data = (kernel_ulong_t) &esdhc_imx25_data,
}, {
.name = "sdhci-esdhc-imx35",
.driver_data = (kernel_ulong_t) &esdhc_imx35_data,
}, {
.name = "sdhci-esdhc-imx51",
.driver_data = (kernel_ulong_t) &esdhc_imx51_data,
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype);
static const struct of_device_id imx_esdhc_dt_ids[] = {
{ .compatible = "fsl,imx25-esdhc", .data = &esdhc_imx25_data, },
{ .compatible = "fsl,imx35-esdhc", .data = &esdhc_imx35_data, },
@ -1531,72 +1515,6 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
}
#endif
static int sdhci_esdhc_imx_probe_nondt(struct platform_device *pdev,
struct sdhci_host *host,
struct pltfm_imx_data *imx_data)
{
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
int err;
if (!host->mmc->parent->platform_data) {
dev_err(mmc_dev(host->mmc), "no board data!\n");
return -EINVAL;
}
imx_data->boarddata = *((struct esdhc_platform_data *)
host->mmc->parent->platform_data);
/* write_protect */
if (boarddata->wp_type == ESDHC_WP_GPIO) {
host->mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
err = mmc_gpiod_request_ro(host->mmc, "wp", 0, 0);
if (err) {
dev_err(mmc_dev(host->mmc),
"failed to request write-protect gpio!\n");
return err;
}
}
/* card_detect */
switch (boarddata->cd_type) {
case ESDHC_CD_GPIO:
err = mmc_gpiod_request_cd(host->mmc, "cd", 0, false, 0);
if (err) {
dev_err(mmc_dev(host->mmc),
"failed to request card-detect gpio!\n");
return err;
}
fallthrough;
case ESDHC_CD_CONTROLLER:
/* we have a working card_detect back */
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
break;
case ESDHC_CD_PERMANENT:
host->mmc->caps |= MMC_CAP_NONREMOVABLE;
break;
case ESDHC_CD_NONE:
break;
}
switch (boarddata->max_bus_width) {
case 8:
host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA;
break;
case 4:
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
break;
case 1:
default:
host->quirks |= SDHCI_QUIRK_FORCE_1_BIT_DATA;
break;
}
return 0;
}
static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
@ -1616,8 +1534,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data = sdhci_pltfm_priv(pltfm_host);
imx_data->socdata = of_id ? of_id->data : (struct esdhc_soc_data *)
pdev->id_entry->driver_data;
imx_data->socdata = of_id->data;
if (imx_data->socdata->flags & ESDHC_FLAG_PMQOS)
cpu_latency_qos_add_request(&imx_data->pm_qos_req, 0);
@ -1713,10 +1630,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
goto disable_ahb_clk;
}
if (of_id)
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
else
err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data);
if (err)
goto disable_ahb_clk;
@ -1929,7 +1843,6 @@ static struct platform_driver sdhci_esdhc_imx_driver = {
.of_match_table = imx_esdhc_dt_ids,
.pm = &sdhci_esdhc_pmops,
},
.id_table = imx_esdhc_devtype,
.probe = sdhci_esdhc_imx_probe,
.remove = sdhci_esdhc_imx_remove,
};

View file

@ -248,7 +248,6 @@ struct sdhci_msm_variant_ops {
struct sdhci_msm_variant_info {
bool mci_removed;
bool restore_dll_config;
bool uses_tassadar_dll;
const struct sdhci_msm_variant_ops *var_ops;
const struct sdhci_msm_offset *offset;
};
@ -2154,18 +2153,10 @@ static const struct sdhci_msm_variant_info sdm845_sdhci_var = {
.offset = &sdhci_msm_v5_offset,
};
static const struct sdhci_msm_variant_info sm8250_sdhci_var = {
.mci_removed = true,
.uses_tassadar_dll = true,
.var_ops = &v5_var_ops,
.offset = &sdhci_msm_v5_offset,
};
static const struct of_device_id sdhci_msm_dt_match[] = {
{.compatible = "qcom,sdhci-msm-v4", .data = &sdhci_msm_mci_var},
{.compatible = "qcom,sdhci-msm-v5", .data = &sdhci_msm_v5_var},
{.compatible = "qcom,sdm845-sdhci", .data = &sdm845_sdhci_var},
{.compatible = "qcom,sm8250-sdhci", .data = &sm8250_sdhci_var},
{.compatible = "qcom,sc7180-sdhci", .data = &sdm845_sdhci_var},
{},
};
@ -2249,7 +2240,6 @@ static int sdhci_msm_probe(struct platform_device *pdev)
msm_host->restore_dll_config = var_info->restore_dll_config;
msm_host->var_ops = var_info->var_ops;
msm_host->offset = var_info->offset;
msm_host->uses_tassadar_dll = var_info->uses_tassadar_dll;
msm_offset = msm_host->offset;
@ -2396,6 +2386,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
if (core_major == 1 && core_minor >= 0x49)
msm_host->updated_ddr_cfg = true;
if (core_major == 1 && core_minor >= 0x71)
msm_host->uses_tassadar_dll = true;
ret = sdhci_msm_register_vreg(msm_host);
if (ret)
goto clk_disable;

View file

@ -624,6 +624,7 @@ static int sdhci_zynqmp_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 8 Taps are available */
tap_max = 8;
break;
default:
break;
}
@ -692,6 +693,7 @@ static int sdhci_zynqmp_sampleclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 30 Taps are available */
tap_max = 30;
break;
default:
break;
}
@ -751,6 +753,7 @@ static int sdhci_versal_sdcardclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 8 Taps are available */
tap_max = 8;
break;
default:
break;
}
@ -817,6 +820,7 @@ static int sdhci_versal_sampleclk_set_phase(struct clk_hw *hw, int degrees)
case MMC_TIMING_MMC_HS200:
/* For 200MHz clock, 30 Taps are available */
tap_max = 30;
break;
default:
break;
}

View file

@ -87,6 +87,9 @@
#define PCIE_GLI_9763E_SCR 0x8E0
#define GLI_9763E_SCR_AXI_REQ BIT(9)
#define PCIE_GLI_9763E_MMC_CTRL 0x960
#define GLI_9763E_HS400_SLOW BIT(3)
#define SDHCI_GLI_9763E_CQE_BASE_ADDR 0x200
#define GLI_9763E_CQE_TRNS_MODE (SDHCI_TRNS_MULTI | \
SDHCI_TRNS_BLK_CNT_EN | \
@ -97,6 +100,10 @@
#define GLI_9755_WT_EN_ON 0x1
#define GLI_9755_WT_EN_OFF 0x0
#define PCI_GLI_9755_PECONF 0x44
#define PCI_GLI_9755_LFCLK GENMASK(14, 12)
#define PCI_GLI_9755_DMACLK BIT(29)
#define PCI_GLI_9755_PLL 0x64
#define PCI_GLI_9755_PLL_LDIV GENMASK(9, 0)
#define PCI_GLI_9755_PLL_PDIV GENMASK(14, 12)
@ -519,6 +526,21 @@ static void sdhci_gl9755_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_enable_clk(host, clk);
}
static void gl9755_hw_setting(struct sdhci_pci_slot *slot)
{
struct pci_dev *pdev = slot->chip->pdev;
u32 value;
gl9755_wt_on(pdev);
pci_read_config_dword(pdev, PCI_GLI_9755_PECONF, &value);
value &= ~PCI_GLI_9755_LFCLK;
value &= ~PCI_GLI_9755_DMACLK;
pci_write_config_dword(pdev, PCI_GLI_9755_PECONF, value);
gl9755_wt_off(pdev);
}
static int gli_probe_slot_gl9750(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
@ -534,6 +556,7 @@ static int gli_probe_slot_gl9755(struct sdhci_pci_slot *slot)
{
struct sdhci_host *host = slot->host;
gl9755_hw_setting(slot);
gli_pcie_enable_msi(slot);
slot->host->mmc->caps2 |= MMC_CAP2_NO_SDIO;
sdhci_enable_v4_mode(host);
@ -764,6 +787,10 @@ static void gli_set_gl9763e(struct sdhci_pci_slot *slot)
value |= GLI_9763E_SCR_AXI_REQ;
pci_write_config_dword(pdev, PCIE_GLI_9763E_SCR, value);
pci_read_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, &value);
value &= ~GLI_9763E_HS400_SLOW;
pci_write_config_dword(pdev, PCIE_GLI_9763E_MMC_CTRL, value);
pci_read_config_dword(pdev, PCIE_GLI_9763E_VHS, &value);
value &= ~GLI_9763E_VHS_REV;
value |= FIELD_PREP(GLI_9763E_VHS_REV, GLI_9763E_VHS_REV_R);

View file

@ -121,10 +121,9 @@ static void pic32_sdhci_shared_bus(struct platform_device *pdev)
writel(bus, host->ioaddr + SDH_SHARED_BUS_CTRL);
}
static int pic32_sdhci_probe_platform(struct platform_device *pdev,
static void pic32_sdhci_probe_platform(struct platform_device *pdev,
struct pic32_sdhci_priv *pdata)
{
int ret = 0;
u32 caps_slot_type;
struct sdhci_host *host = platform_get_drvdata(pdev);
@ -133,8 +132,6 @@ static int pic32_sdhci_probe_platform(struct platform_device *pdev,
caps_slot_type = (host->caps & SDH_CAPS_SDH_SLOT_TYPE_MASK) >> 30;
if (caps_slot_type == SDH_SLOT_TYPE_SHARED_BUS)
pic32_sdhci_shared_bus(pdev);
return ret;
}
static int pic32_sdhci_probe(struct platform_device *pdev)
@ -193,11 +190,7 @@ static int pic32_sdhci_probe(struct platform_device *pdev)
if (ret)
goto err_base_clk;
ret = pic32_sdhci_probe_platform(pdev, sdhci_pdata);
if (ret) {
dev_err(&pdev->dev, "failed to probe platform!\n");
goto err_base_clk;
}
pic32_sdhci_probe_platform(pdev, sdhci_pdata);
ret = sdhci_add_host(host);
if (ret)

View file

@ -788,7 +788,7 @@ static struct platform_driver sdhci_sprd_driver = {
.driver = {
.name = "sdhci_sprd_r11",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sdhci_sprd_of_match),
.of_match_table = sdhci_sprd_of_match,
.pm = &sdhci_sprd_pm_ops,
},
};

View file

@ -523,7 +523,7 @@ static struct platform_driver sdhci_st_driver = {
.name = "sdhci-st",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = &sdhci_st_pmops,
.of_match_table = of_match_ptr(st_sdhci_match),
.of_match_table = st_sdhci_match,
},
};

View file

@ -1272,7 +1272,7 @@ static void tegra_sdhci_set_timeout(struct sdhci_host *host,
* busy wait mode.
*/
val = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
if (cmd && cmd->busy_timeout >= 11 * HZ)
if (cmd && cmd->busy_timeout >= 11 * MSEC_PER_SEC)
val |= SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;
else
val &= ~SDHCI_MISC_CTRL_ERASE_TIMEOUT_LIMIT;

View file

@ -651,11 +651,13 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
struct device_node *np,
struct xenon_emmc_phy_params *params)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct xenon_priv *priv = sdhci_pltfm_priv(pltfm_host);
int ret = 0;
const char *name;
struct resource iomem;
if (of_device_is_compatible(np, "marvell,armada-3700-sdhci"))
if (priv->hw_version == XENON_A3700)
params->pad_ctrl.set_soc_pad = armada_3700_soc_pad_voltage_set;
else
return 0;
@ -689,35 +691,37 @@ static int get_dt_pad_ctrl_data(struct sdhci_host *host,
return ret;
}
static int xenon_emmc_phy_parse_param_dt(struct sdhci_host *host,
struct device_node *np,
struct xenon_emmc_phy_params *params)
static int xenon_emmc_phy_parse_params(struct sdhci_host *host,
struct device *dev,
struct xenon_emmc_phy_params *params)
{
u32 value;
params->slow_mode = false;
if (of_property_read_bool(np, "marvell,xenon-phy-slow-mode"))
if (device_property_read_bool(dev, "marvell,xenon-phy-slow-mode"))
params->slow_mode = true;
params->znr = XENON_ZNR_DEF_VALUE;
if (!of_property_read_u32(np, "marvell,xenon-phy-znr", &value))
if (!device_property_read_u32(dev, "marvell,xenon-phy-znr", &value))
params->znr = value & XENON_ZNR_MASK;
params->zpr = XENON_ZPR_DEF_VALUE;
if (!of_property_read_u32(np, "marvell,xenon-phy-zpr", &value))
if (!device_property_read_u32(dev, "marvell,xenon-phy-zpr", &value))
params->zpr = value & XENON_ZPR_MASK;
params->nr_tun_times = XENON_TUN_CONSECUTIVE_TIMES;
if (!of_property_read_u32(np, "marvell,xenon-phy-nr-success-tun",
&value))
if (!device_property_read_u32(dev, "marvell,xenon-phy-nr-success-tun",
&value))
params->nr_tun_times = value & XENON_TUN_CONSECUTIVE_TIMES_MASK;
params->tun_step_divider = XENON_TUNING_STEP_DIVIDER;
if (!of_property_read_u32(np, "marvell,xenon-phy-tun-step-divider",
&value))
if (!device_property_read_u32(dev, "marvell,xenon-phy-tun-step-divider",
&value))
params->tun_step_divider = value & 0xFF;
return get_dt_pad_ctrl_data(host, np, params);
if (dev->of_node)
return get_dt_pad_ctrl_data(host, dev->of_node, params);
return 0;
}
/* Set SoC PHY Voltage PAD */
@ -811,7 +815,7 @@ int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios)
return ret;
}
static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
static int xenon_add_phy(struct device *dev, struct sdhci_host *host,
const char *phy_name)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -830,15 +834,15 @@ static int xenon_add_phy(struct device_node *np, struct sdhci_host *host,
if (ret)
return ret;
return xenon_emmc_phy_parse_param_dt(host, np, priv->phy_params);
return xenon_emmc_phy_parse_params(host, dev, priv->phy_params);
}
int xenon_phy_parse_dt(struct device_node *np, struct sdhci_host *host)
int xenon_phy_parse_params(struct device *dev, struct sdhci_host *host)
{
const char *phy_type = NULL;
if (!of_property_read_string(np, "marvell,xenon-phy-type", &phy_type))
return xenon_add_phy(np, host, phy_type);
if (!device_property_read_string(dev, "marvell,xenon-phy-type", &phy_type))
return xenon_add_phy(dev, host, phy_type);
return xenon_add_phy(np, host, "emmc 5.1 phy");
return xenon_add_phy(dev, host, "emmc 5.1 phy");
}

View file

@ -11,6 +11,7 @@
* Special thanks to Video BG4 project team.
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/ktime.h>
#include <linux/module.h>
@ -247,6 +248,16 @@ static void xenon_voltage_switch(struct sdhci_host *host)
sdhci_readw(host, SDHCI_HOST_CONTROL2);
}
static unsigned int xenon_get_max_clock(struct sdhci_host *host)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
if (pltfm_host->clk)
return sdhci_pltfm_clk_get_max_clock(host);
else
return pltfm_host->clock;
}
static const struct sdhci_ops sdhci_xenon_ops = {
.voltage_switch = xenon_voltage_switch,
.set_clock = sdhci_set_clock,
@ -254,7 +265,7 @@ static const struct sdhci_ops sdhci_xenon_ops = {
.set_bus_width = sdhci_set_bus_width,
.reset = xenon_reset,
.set_uhs_signaling = xenon_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_max_clock = xenon_get_max_clock,
};
static const struct sdhci_pltfm_data sdhci_xenon_pdata = {
@ -407,9 +418,9 @@ static void xenon_replace_mmc_host_ops(struct sdhci_host *host)
* Refer to XENON_SYS_CFG_INFO register
* tun-count: the interval between re-tuning
*/
static int xenon_probe_dt(struct platform_device *pdev)
static int xenon_probe_params(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct sdhci_host *host = platform_get_drvdata(pdev);
struct mmc_host *mmc = host->mmc;
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -418,11 +429,11 @@ static int xenon_probe_dt(struct platform_device *pdev)
u32 tuning_count;
/* Disable HS200 on Armada AP806 */
if (of_device_is_compatible(np, "marvell,armada-ap806-sdhci"))
if (priv->hw_version == XENON_AP806)
host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
sdhc_id = 0x0;
if (!of_property_read_u32(np, "marvell,xenon-sdhc-id", &sdhc_id)) {
if (!device_property_read_u32(dev, "marvell,xenon-sdhc-id", &sdhc_id)) {
nr_sdhc = sdhci_readl(host, XENON_SYS_CFG_INFO);
nr_sdhc &= XENON_NR_SUPPORTED_SLOT_MASK;
if (unlikely(sdhc_id > nr_sdhc)) {
@ -434,8 +445,8 @@ static int xenon_probe_dt(struct platform_device *pdev)
priv->sdhc_id = sdhc_id;
tuning_count = XENON_DEF_TUNING_COUNT;
if (!of_property_read_u32(np, "marvell,xenon-tun-count",
&tuning_count)) {
if (!device_property_read_u32(dev, "marvell,xenon-tun-count",
&tuning_count)) {
if (unlikely(tuning_count >= XENON_TMR_RETUN_NO_PRESENT)) {
dev_err(mmc_dev(mmc), "Wrong Re-tuning Count. Set default value %d\n",
XENON_DEF_TUNING_COUNT);
@ -444,7 +455,7 @@ static int xenon_probe_dt(struct platform_device *pdev)
}
priv->tuning_count = tuning_count;
return xenon_phy_parse_dt(np, host);
return xenon_phy_parse_params(dev, host);
}
static int xenon_sdhc_prepare(struct sdhci_host *host)
@ -483,6 +494,7 @@ static void xenon_sdhc_unprepare(struct sdhci_host *host)
static int xenon_probe(struct platform_device *pdev)
{
struct sdhci_pltfm_host *pltfm_host;
struct device *dev = &pdev->dev;
struct sdhci_host *host;
struct xenon_priv *priv;
int err;
@ -495,43 +507,47 @@ static int xenon_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
priv = sdhci_pltfm_priv(pltfm_host);
priv->hw_version = (unsigned long)device_get_match_data(&pdev->dev);
/*
* Link Xenon specific mmc_host_ops function,
* to replace standard ones in sdhci_ops.
*/
xenon_replace_mmc_host_ops(host);
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(pltfm_host->clk)) {
err = PTR_ERR(pltfm_host->clk);
dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
goto free_pltfm;
}
err = clk_prepare_enable(pltfm_host->clk);
if (err)
goto free_pltfm;
priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(priv->axi_clk)) {
err = PTR_ERR(priv->axi_clk);
if (err == -EPROBE_DEFER)
goto err_clk;
} else {
err = clk_prepare_enable(priv->axi_clk);
if (dev->of_node) {
pltfm_host->clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(pltfm_host->clk)) {
err = PTR_ERR(pltfm_host->clk);
dev_err(&pdev->dev, "Failed to setup input clk: %d\n", err);
goto free_pltfm;
}
err = clk_prepare_enable(pltfm_host->clk);
if (err)
goto err_clk;
goto free_pltfm;
priv->axi_clk = devm_clk_get(&pdev->dev, "axi");
if (IS_ERR(priv->axi_clk)) {
err = PTR_ERR(priv->axi_clk);
if (err == -EPROBE_DEFER)
goto err_clk;
} else {
err = clk_prepare_enable(priv->axi_clk);
if (err)
goto err_clk;
}
}
err = mmc_of_parse(host->mmc);
if (err)
goto err_clk_axi;
sdhci_get_of_property(pdev);
sdhci_get_property(pdev);
xenon_set_acg(host, false);
/* Xenon specific dt parse */
err = xenon_probe_dt(pdev);
/* Xenon specific parameters parse */
err = xenon_probe_params(pdev);
if (err)
goto err_clk_axi;
@ -667,18 +683,29 @@ static const struct dev_pm_ops sdhci_xenon_dev_pm_ops = {
};
static const struct of_device_id sdhci_xenon_dt_ids[] = {
{ .compatible = "marvell,armada-ap806-sdhci",},
{ .compatible = "marvell,armada-cp110-sdhci",},
{ .compatible = "marvell,armada-3700-sdhci",},
{ .compatible = "marvell,armada-ap806-sdhci", .data = (void *)XENON_AP806},
{ .compatible = "marvell,armada-cp110-sdhci", .data = (void *)XENON_CP110},
{ .compatible = "marvell,armada-3700-sdhci", .data = (void *)XENON_A3700},
{}
};
MODULE_DEVICE_TABLE(of, sdhci_xenon_dt_ids);
#ifdef CONFIG_ACPI
static const struct acpi_device_id sdhci_xenon_acpi_ids[] = {
{ .id = "MRVL0002", XENON_AP806},
{ .id = "MRVL0003", XENON_AP807},
{ .id = "MRVL0004", XENON_CP110},
{}
};
MODULE_DEVICE_TABLE(acpi, sdhci_xenon_acpi_ids);
#endif
static struct platform_driver sdhci_xenon_driver = {
.driver = {
.name = "xenon-sdhci",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = sdhci_xenon_dt_ids,
.acpi_match_table = ACPI_PTR(sdhci_xenon_acpi_ids),
.pm = &sdhci_xenon_dev_pm_ops,
},
.probe = xenon_probe,

View file

@ -53,6 +53,13 @@
#define XENON_CTRL_HS200 0x5
#define XENON_CTRL_HS400 0x6
enum xenon_variant {
XENON_A3700,
XENON_AP806,
XENON_AP807,
XENON_CP110
};
struct xenon_priv {
unsigned char tuning_count;
/* idx of SDHC */
@ -90,11 +97,12 @@ struct xenon_priv {
void *phy_params;
struct xenon_emmc_phy_regs *emmc_phy_regs;
bool restore_needed;
enum xenon_variant hw_version;
};
int xenon_phy_adj(struct sdhci_host *host, struct mmc_ios *ios);
int xenon_phy_parse_dt(struct device_node *np,
struct sdhci_host *host);
int xenon_phy_parse_params(struct device *dev,
struct sdhci_host *host);
void xenon_soc_pad_ctrl(struct sdhci_host *host,
unsigned char signal_voltage);
#endif

View file

@ -3994,10 +3994,10 @@ void __sdhci_read_caps(struct sdhci_host *host, const u16 *ver,
if (host->v4_mode)
sdhci_do_enable_v4_mode(host);
of_property_read_u64(mmc_dev(host->mmc)->of_node,
"sdhci-caps-mask", &dt_caps_mask);
of_property_read_u64(mmc_dev(host->mmc)->of_node,
"sdhci-caps", &dt_caps);
device_property_read_u64(mmc_dev(host->mmc),
"sdhci-caps-mask", &dt_caps_mask);
device_property_read_u64(mmc_dev(host->mmc),
"sdhci-caps", &dt_caps);
v = ver ? *ver : sdhci_readw(host, SDHCI_HOST_VERSION);
host->version = (v & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;

View file

@ -26,6 +26,7 @@
#include <linux/mmc/sdio.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
@ -1515,7 +1516,7 @@ static struct platform_driver sunxi_mmc_driver = {
.driver = {
.name = "sunxi-mmc",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(sunxi_mmc_of_match),
.of_match_table = sunxi_mmc_of_match,
.pm = &sunxi_mmc_pm_ops,
},
.probe = sunxi_mmc_probe,

View file

@ -174,8 +174,7 @@ static int tmio_mmc_probe(struct platform_device *pdev)
if (ret)
goto host_remove;
pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
(unsigned long)host->ctl, irq);
pr_info("%s at 0x%p irq %d\n", mmc_hostname(host->mmc), host->ctl, irq);
return 0;

View file

@ -42,7 +42,6 @@
#define CTL_DMA_ENABLE 0xd8
#define CTL_RESET_SD 0xe0
#define CTL_VERSION 0xe2
#define CTL_SDIF_MODE 0xe6
/* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */
#define TMIO_STOP_STP BIT(0)
@ -81,7 +80,11 @@
#define CLK_CTL_SCLKEN BIT(8)
/* Definitions for values the CTL_SD_MEM_CARD_OPT register can take */
#define CARD_OPT_TOP_MASK 0xf0
#define CARD_OPT_TOP_SHIFT 4
#define CARD_OPT_EXTOP BIT(9) /* first appeared on R-Car Gen3 SDHI */
#define CARD_OPT_WIDTH8 BIT(13)
#define CARD_OPT_ALWAYS1 BIT(14)
#define CARD_OPT_WIDTH BIT(15)
/* Definitions for values the CTL_SDIO_STATUS register can take */
@ -180,6 +183,7 @@ struct tmio_mmc_host {
void (*reset)(struct tmio_mmc_host *host);
bool (*check_retune)(struct tmio_mmc_host *host);
void (*fixup_request)(struct tmio_mmc_host *host, struct mmc_request *mrq);
unsigned int (*get_timeout_cycles)(struct tmio_mmc_host *host);
void (*prepare_hs400_tuning)(struct tmio_mmc_host *host);
void (*hs400_downgrade)(struct tmio_mmc_host *host);

View file

@ -796,8 +796,10 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
spin_unlock_irqrestore(&host->lock, flags);
if (mrq->cmd->error || (mrq->data && mrq->data->error))
if (mrq->cmd->error || (mrq->data && mrq->data->error)) {
tmio_mmc_ack_mmc_irqs(host, TMIO_MASK_IRQ); /* Clear all */
tmio_mmc_abort_dma(host);
}
/* Error means retune, but executed command was still successful */
if (host->check_retune && host->check_retune(host))
@ -885,6 +887,22 @@ static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
sd_ctrl_write16(host, CTL_SD_MEM_CARD_OPT, reg);
}
static unsigned int tmio_mmc_get_timeout_cycles(struct tmio_mmc_host *host)
{
u16 val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
val = (val & CARD_OPT_TOP_MASK) >> CARD_OPT_TOP_SHIFT;
return 1 << (13 + val);
}
static void tmio_mmc_max_busy_timeout(struct tmio_mmc_host *host)
{
unsigned int clk_rate = host->mmc->actual_clock ?: host->mmc->f_max;
host->mmc->max_busy_timeout = host->get_timeout_cycles(host) /
(clk_rate / MSEC_PER_SEC);
}
/* Set MMC clock / power.
* Note: This controller uses a simple divider scheme therefore it cannot
* run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
@ -943,6 +961,9 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
}
if (host->pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT)
tmio_mmc_max_busy_timeout(host);
/* Let things settle. delay taken from winCE driver */
usleep_range(140, 200);
if (PTR_ERR(host->mrq) == -EINTR)
@ -1099,6 +1120,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host)
if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
_host->write16_hook = NULL;
if (pdata->flags & TMIO_MMC_USE_BUSY_TIMEOUT && !_host->get_timeout_cycles)
_host->get_timeout_cycles = tmio_mmc_get_timeout_cycles;
_host->set_pwr = pdata->set_pwr;
ret = tmio_mmc_init_ocr(_host);

View file

@ -586,6 +586,7 @@ static int uniphier_sd_probe(struct platform_device *pdev)
tmio_data = &priv->tmio_data;
tmio_data->flags |= TMIO_MMC_32BIT_DATA_PORT;
tmio_data->flags |= TMIO_MMC_USE_BUSY_TIMEOUT;
host = tmio_mmc_host_alloc(pdev, tmio_data);
if (IS_ERR(host))

View file

@ -55,7 +55,12 @@
*/
#define TMIO_MMC_HAS_IDLE_WAIT BIT(4)
/* BIT(5) is unused */
/*
* Use the busy timeout feature. Probably all TMIO versions support it. Yet,
* we don't have documentation for old variants, so we enable only known good
* variants with this flag. Can be removed once all variants are known good.
*/
#define TMIO_MMC_USE_BUSY_TIMEOUT BIT(5)
/*
* Some controllers have CMD12 automatically

View file

@ -60,6 +60,8 @@ struct mmc_ios {
#define MMC_TIMING_MMC_DDR52 8
#define MMC_TIMING_MMC_HS200 9
#define MMC_TIMING_MMC_HS400 10
#define MMC_TIMING_SD_EXP 11
#define MMC_TIMING_SD_EXP_1_2V 12
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
@ -173,6 +175,9 @@ struct mmc_host_ops {
*/
int (*multi_io_quirk)(struct mmc_card *card,
unsigned int direction, int blk_size);
/* Initialize an SD express card, mandatory for MMC_CAP2_SD_EXP. */
int (*init_sd_express)(struct mmc_host *host, struct mmc_ios *ios);
};
struct mmc_cqe_ops {
@ -358,6 +363,8 @@ struct mmc_host {
#define MMC_CAP2_HS200_1_2V_SDR (1 << 6) /* can support */
#define MMC_CAP2_HS200 (MMC_CAP2_HS200_1_8V_SDR | \
MMC_CAP2_HS200_1_2V_SDR)
#define MMC_CAP2_SD_EXP (1 << 7) /* SD express via PCIe */
#define MMC_CAP2_SD_EXP_1_2V (1 << 8) /* SD express 1.2V */
#define MMC_CAP2_CD_ACTIVE_HIGH (1 << 10) /* Card-detect signal active high */
#define MMC_CAP2_RO_ACTIVE_HIGH (1 << 11) /* Write-protect signal active high */
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */

View file

@ -82,6 +82,7 @@
#define MS_OC_INT_EN (1 << 23)
#define SD_OC_INT_EN (1 << 22)
#define RTSX_DUM_REG 0x1C
/*
* macros for easy use
@ -658,6 +659,23 @@
#define PM_WAKE_EN 0x01
#define PM_CTRL4 0xFF47
/* FW config info register */
#define RTS5261_FW_CFG_INFO0 0xFF50
#define RTS5261_FW_EXPRESS_TEST_MASK (0x01 << 0)
#define RTS5261_FW_EA_MODE_MASK (0x01 << 5)
#define RTS5261_FW_CFG0 0xFF54
#define RTS5261_FW_ENTER_EXPRESS (0x01 << 0)
#define RTS5261_FW_CFG1 0xFF55
#define RTS5261_SYS_CLK_SEL_MCU_CLK (0x01 << 7)
#define RTS5261_CRC_CLK_SEL_MCU_CLK (0x01 << 6)
#define RTS5261_FAKE_MCU_CLOCK_GATING (0x01 << 5)
#define RTS5261_MCU_BUS_SEL_MASK (0x01 << 4)
#define RTS5261_MCU_CLOCK_SEL_MASK (0x03 << 2)
#define RTS5261_MCU_CLOCK_SEL_16M (0x01 << 2)
#define RTS5261_MCU_CLOCK_GATING (0x01 << 1)
#define RTS5261_DRIVER_ENABLE_FW (0x01 << 0)
#define REG_CFG_OOBS_OFF_TIMER 0xFEA6
#define REG_CFG_OOBS_ON_TIMER 0xFEA7
#define REG_CFG_VCM_ON_TIMER 0xFEA8
@ -701,6 +719,13 @@
#define RTS5260_DVCC_TUNE_MASK 0x70
#define RTS5260_DVCC_33 0x70
/*RTS5261*/
#define RTS5261_LDO1_CFG0 0xFF72
#define RTS5261_LDO1_OCP_THD_MASK (0x07 << 5)
#define RTS5261_LDO1_OCP_EN (0x01 << 4)
#define RTS5261_LDO1_OCP_LMT_THD_MASK (0x03 << 2)
#define RTS5261_LDO1_OCP_LMT_EN (0x01 << 1)
#define LDO_VCC_CFG1 0xFF73
#define LDO_VCC_REF_TUNE_MASK 0x30
#define LDO_VCC_REF_1V2 0x20
@ -741,6 +766,8 @@
#define RTS5260_AUTOLOAD_CFG4 0xFF7F
#define RTS5260_MIMO_DISABLE 0x8A
/*RTS5261*/
#define RTS5261_AUX_CLK_16M_EN (1 << 5)
#define RTS5260_REG_GPIO_CTL0 0xFC1A
#define RTS5260_REG_GPIO_MASK 0x01
@ -1193,6 +1220,7 @@ struct rtsx_pcr {
#define EXTRA_CAPS_MMC_HS200 (1 << 4)
#define EXTRA_CAPS_MMC_8BIT (1 << 5)
#define EXTRA_CAPS_NO_MMC (1 << 7)
#define EXTRA_CAPS_SD_EXPRESS (1 << 8)
u32 extra_caps;
#define IC_VER_A 0
@ -1247,6 +1275,8 @@ struct rtsx_pcr {
#define PCI_PID(pcr) ((pcr)->pci->device)
#define is_version(pcr, pid, ver) \
(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version == (ver))
#define is_version_higher_than(pcr, pid, ver) \
(CHK_PCI_PID(pcr, pid) && (pcr)->ic_version > (ver))
#define pcr_dbg(pcr, fmt, arg...) \
dev_dbg(&(pcr)->pci->dev, fmt, ##arg)