Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | // SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2015, Google, Inc * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com> */ #include <dm.h> #include <errno.h> #include <log.h> #include <malloc.h> #include <mapmem.h> #include <mmc.h> #include <sdhci.h> #include <acpi/acpigen.h> #include <acpi/acpi_device.h> #include <acpi/acpi_dp.h> #include <asm-generic/gpio.h> #include <dm/acpi.h> /* Type of MMC device */ enum { TYPE_SD, TYPE_EMMC, }; struct pci_mmc_plat { struct mmc_config cfg; struct mmc mmc; }; struct pci_mmc_priv { struct sdhci_host host; void *base; struct gpio_desc cd_gpio; }; static int pci_mmc_probe(struct udevice *dev) { struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); struct pci_mmc_plat *plat = dev_get_plat(dev); struct pci_mmc_priv *priv = dev_get_priv(dev); struct sdhci_host *host = &priv->host; struct blk_desc *desc; int ret; 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); host->ioaddr = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, 0, 0, PCI_REGION_TYPE, PCI_REGION_MEM); host->name = dev->name; host->cd_gpio = priv->cd_gpio; host->mmc = &plat->mmc; host->mmc->dev = dev; 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); } static int pci_mmc_of_to_plat(struct udevice *dev) { if (CONFIG_IS_ENABLED(DM_GPIO)) { struct pci_mmc_priv *priv = dev_get_priv(dev); int ret; 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); } return 0; } static int pci_mmc_bind(struct udevice *dev) { struct pci_mmc_plat *plat = dev_get_plat(dev); return sdhci_bind(dev, &plat->mmc, &plat->cfg); } __maybe_unused 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; if (!dev_has_ofnode(dev)) return 0; if (dev_get_driver_data(dev) == TYPE_EMMC) return 0; 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 = { #ifdef CONFIG_ACPIGEN .fill_ssdt = pci_mmc_acpi_fill_ssdt, #endif }; static const struct udevice_id pci_mmc_match[] = { { .compatible = "intel,apl-sd", .data = TYPE_SD }, { .compatible = "intel,apl-emmc", .data = TYPE_EMMC }, { } }; U_BOOT_DRIVER(pci_mmc) = { .name = "pci_mmc", .id = UCLASS_MMC, .of_match = pci_mmc_match, .bind = pci_mmc_bind, .of_to_plat = pci_mmc_of_to_plat, .probe = pci_mmc_probe, .ops = &sdhci_ops, .priv_auto = sizeof(struct pci_mmc_priv), .plat_auto = sizeof(struct pci_mmc_plat), ACPI_OPS_PTR(&pci_mmc_acpi_ops) }; static struct pci_device_id mmc_supported[] = { { PCI_DEVICE_CLASS(PCI_CLASS_SYSTEM_SDHCI << 8, 0xffff00) }, {}, }; U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported); |