2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2015-01-28 05:13:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015, Google, Inc
|
|
|
|
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common.h>
|
2017-07-31 02:24:01 +00:00
|
|
|
#include <dm.h>
|
2015-01-28 05:13:39 +00:00
|
|
|
#include <errno.h>
|
2020-07-08 03:32:12 +00:00
|
|
|
#include <log.h>
|
2015-01-28 05:13:39 +00:00
|
|
|
#include <malloc.h>
|
2017-07-31 02:24:01 +00:00
|
|
|
#include <mapmem.h>
|
2021-01-14 03:29:54 +00:00
|
|
|
#include <mmc.h>
|
2015-01-28 05:13:39 +00:00
|
|
|
#include <sdhci.h>
|
2020-07-08 03:32:12 +00:00
|
|
|
#include <acpi/acpigen.h>
|
|
|
|
#include <acpi/acpi_device.h>
|
|
|
|
#include <acpi/acpi_dp.h>
|
|
|
|
#include <asm-generic/gpio.h>
|
|
|
|
#include <dm/acpi.h>
|
2015-01-28 05:13:39 +00:00
|
|
|
|
2021-01-14 03:29:52 +00:00
|
|
|
/* Type of MMC device */
|
|
|
|
enum {
|
|
|
|
TYPE_SD,
|
|
|
|
TYPE_EMMC,
|
|
|
|
};
|
|
|
|
|
2017-07-31 02:24:01 +00:00
|
|
|
struct pci_mmc_plat {
|
|
|
|
struct mmc_config cfg;
|
|
|
|
struct mmc mmc;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct pci_mmc_priv {
|
|
|
|
struct sdhci_host host;
|
|
|
|
void *base;
|
2020-07-08 03:32:12 +00:00
|
|
|
struct gpio_desc cd_gpio;
|
2017-07-31 02:24:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int pci_mmc_probe(struct udevice *dev)
|
2015-01-28 05:13:39 +00:00
|
|
|
{
|
2017-07-31 02:24:01 +00:00
|
|
|
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
|
2020-12-03 23:55:20 +00:00
|
|
|
struct pci_mmc_plat *plat = dev_get_plat(dev);
|
2017-07-31 02:24:01 +00:00
|
|
|
struct pci_mmc_priv *priv = dev_get_priv(dev);
|
|
|
|
struct sdhci_host *host = &priv->host;
|
2021-01-14 03:29:54 +00:00
|
|
|
struct blk_desc *desc;
|
2015-01-28 05:13:39 +00:00
|
|
|
int ret;
|
2017-07-31 02:24:01 +00:00
|
|
|
|
2021-01-14 03:29:54 +00:00
|
|
|
ret = mmc_of_parse(dev, &plat->cfg);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
desc = mmc_get_blk_desc(&plat->mmc);
|
|
|
|
desc->removable = !(plat->cfg.host_caps & MMC_CAP_NONREMOVABLE);
|
|
|
|
|
2023-10-11 11:00:52 +00:00
|
|
|
host->ioaddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0,
|
|
|
|
PCI_REGION_TYPE, PCI_REGION_MEM);
|
2017-07-31 02:24:01 +00:00
|
|
|
host->name = dev->name;
|
2021-03-15 05:00:08 +00:00
|
|
|
host->cd_gpio = priv->cd_gpio;
|
2019-08-06 02:47:56 +00:00
|
|
|
host->mmc = &plat->mmc;
|
|
|
|
host->mmc->dev = dev;
|
2017-07-31 02:24:01 +00:00
|
|
|
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
host->mmc->priv = &priv->host;
|
|
|
|
upriv->mmc = host->mmc;
|
|
|
|
|
|
|
|
return sdhci_probe(dev);
|
2015-01-28 05:13:39 +00:00
|
|
|
}
|
2017-07-31 02:24:01 +00:00
|
|
|
|
2020-12-03 23:55:21 +00:00
|
|
|
static int pci_mmc_of_to_plat(struct udevice *dev)
|
2020-07-08 03:32:12 +00:00
|
|
|
{
|
2020-11-06 12:20:44 +00:00
|
|
|
if (CONFIG_IS_ENABLED(DM_GPIO)) {
|
|
|
|
struct pci_mmc_priv *priv = dev_get_priv(dev);
|
2021-03-15 05:00:08 +00:00
|
|
|
int ret;
|
2020-07-08 03:32:12 +00:00
|
|
|
|
2021-03-15 05:00:08 +00:00
|
|
|
ret = gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio,
|
|
|
|
GPIOD_IS_IN);
|
|
|
|
log_debug("cd-gpio %s done, ret=%d\n", dev->name, ret);
|
2020-11-06 12:20:44 +00:00
|
|
|
}
|
2020-07-08 03:32:12 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-31 02:24:01 +00:00
|
|
|
static int pci_mmc_bind(struct udevice *dev)
|
|
|
|
{
|
2020-12-03 23:55:20 +00:00
|
|
|
struct pci_mmc_plat *plat = dev_get_plat(dev);
|
2017-07-31 02:24:01 +00:00
|
|
|
|
|
|
|
return sdhci_bind(dev, &plat->mmc, &plat->cfg);
|
|
|
|
}
|
|
|
|
|
2022-06-12 12:53:48 +00:00
|
|
|
__maybe_unused
|
2020-07-08 03:32:12 +00:00
|
|
|
static int pci_mmc_acpi_fill_ssdt(const struct udevice *dev,
|
|
|
|
struct acpi_ctx *ctx)
|
|
|
|
{
|
|
|
|
struct pci_mmc_priv *priv = dev_get_priv(dev);
|
|
|
|
char path[ACPI_PATH_MAX];
|
|
|
|
struct acpi_gpio gpio;
|
|
|
|
struct acpi_dp *dp;
|
|
|
|
int ret;
|
|
|
|
|
2020-12-19 17:40:13 +00:00
|
|
|
if (!dev_has_ofnode(dev))
|
2020-07-08 03:32:12 +00:00
|
|
|
return 0;
|
2021-01-14 03:29:52 +00:00
|
|
|
if (dev_get_driver_data(dev) == TYPE_EMMC)
|
|
|
|
return 0;
|
2020-07-08 03:32:12 +00:00
|
|
|
|
|
|
|
ret = gpio_get_acpi(&priv->cd_gpio, &gpio);
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("gpio", ret);
|
|
|
|
gpio.type = ACPI_GPIO_TYPE_INTERRUPT;
|
|
|
|
gpio.pull = ACPI_GPIO_PULL_NONE;
|
|
|
|
gpio.irq.mode = ACPI_IRQ_EDGE_TRIGGERED;
|
|
|
|
gpio.irq.polarity = ACPI_IRQ_ACTIVE_BOTH;
|
|
|
|
gpio.irq.shared = ACPI_IRQ_SHARED;
|
|
|
|
gpio.irq.wake = ACPI_IRQ_WAKE;
|
|
|
|
gpio.interrupt_debounce_timeout = 10000; /* 100ms */
|
|
|
|
|
|
|
|
/* Use device path as the Scope for the SSDT */
|
|
|
|
ret = acpi_device_path(dev, path, sizeof(path));
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("path", ret);
|
|
|
|
acpigen_write_scope(ctx, path);
|
|
|
|
acpigen_write_name(ctx, "_CRS");
|
|
|
|
|
|
|
|
/* Write GpioInt() as default (if set) or custom from devicetree */
|
|
|
|
acpigen_write_resourcetemplate_header(ctx);
|
|
|
|
acpi_device_write_gpio(ctx, &gpio);
|
|
|
|
acpigen_write_resourcetemplate_footer(ctx);
|
|
|
|
|
|
|
|
/* Bind the cd-gpio name to the GpioInt() resource */
|
|
|
|
dp = acpi_dp_new_table("_DSD");
|
|
|
|
if (!dp)
|
|
|
|
return -ENOMEM;
|
|
|
|
acpi_dp_add_gpio(dp, "cd-gpio", path, 0, 0, 1);
|
|
|
|
ret = acpi_dp_write(ctx, dp);
|
|
|
|
if (ret)
|
|
|
|
return log_msg_ret("cd", ret);
|
|
|
|
|
|
|
|
acpigen_pop_len(ctx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct acpi_ops pci_mmc_acpi_ops = {
|
2022-06-12 12:53:48 +00:00
|
|
|
#ifdef CONFIG_ACPIGEN
|
2020-07-08 03:32:12 +00:00
|
|
|
.fill_ssdt = pci_mmc_acpi_fill_ssdt,
|
2022-06-12 12:53:48 +00:00
|
|
|
#endif
|
2020-07-08 03:32:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct udevice_id pci_mmc_match[] = {
|
2021-01-14 03:29:52 +00:00
|
|
|
{ .compatible = "intel,apl-sd", .data = TYPE_SD },
|
|
|
|
{ .compatible = "intel,apl-emmc", .data = TYPE_EMMC },
|
2020-07-08 03:32:12 +00:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
2017-07-31 02:24:01 +00:00
|
|
|
U_BOOT_DRIVER(pci_mmc) = {
|
|
|
|
.name = "pci_mmc",
|
|
|
|
.id = UCLASS_MMC,
|
2020-07-08 03:32:12 +00:00
|
|
|
.of_match = pci_mmc_match,
|
2017-07-31 02:24:01 +00:00
|
|
|
.bind = pci_mmc_bind,
|
2020-12-03 23:55:21 +00:00
|
|
|
.of_to_plat = pci_mmc_of_to_plat,
|
2017-07-31 02:24:01 +00:00
|
|
|
.probe = pci_mmc_probe,
|
|
|
|
.ops = &sdhci_ops,
|
2020-12-03 23:55:17 +00:00
|
|
|
.priv_auto = sizeof(struct pci_mmc_priv),
|
2020-12-03 23:55:18 +00:00
|
|
|
.plat_auto = sizeof(struct pci_mmc_plat),
|
2020-07-08 03:32:12 +00:00
|
|
|
ACPI_OPS_PTR(&pci_mmc_acpi_ops)
|
2017-07-31 02:24:01 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct pci_device_id mmc_supported[] = {
|
2017-08-09 07:21:00 +00:00
|
|
|
{ PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_SDHCI << 8, 0xffff00) },
|
2017-07-31 02:24:01 +00:00
|
|
|
{},
|
|
|
|
};
|
|
|
|
|
|
|
|
U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported);
|