|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
| 2 | +/* |
| 3 | + * Host interface (LPC or eSPI) configuration on Nuvoton BMC |
| 4 | + * Copyright (c) 2022 Nuvoton Technology Corp. |
| 5 | + */ |
| 6 | + |
| 7 | +#include <common.h> |
| 8 | +#include <dm.h> |
| 9 | +#include <regmap.h> |
| 10 | +#include <syscon.h> |
| 11 | +#include <asm/io.h> |
| 12 | +#include <dm/device_compat.h> |
| 13 | +#include <linux/bitfield.h> |
| 14 | + |
| 15 | +#define SMC_CTL_REG_ADDR 0xc0001001 |
| 16 | +#define SMC_CTL_HOSTWAIT 0x80 |
| 17 | + |
| 18 | +/* GCR Register Offsets */ |
| 19 | +#define HIFCR 0x50 |
| 20 | +#define MFSEL1 0x260 |
| 21 | +#define MFSEL4 0x26c |
| 22 | + |
| 23 | +/* ESPI Register offsets */ |
| 24 | +#define ESPICFG 0x4 |
| 25 | +#define ESPIHINDP 0x80 |
| 26 | + |
| 27 | +/* MFSEL bit fileds */ |
| 28 | +#define MFSEL1_LPCSEL BIT(26) |
| 29 | +#define MFSEL4_ESPISEL BIT(8) |
| 30 | + |
| 31 | +/* ESPICFG bit fileds */ |
| 32 | +#define CHSUPP_MASK GENMASK(27, 24) |
| 33 | +#define IOMODE_MASK GENMASK(9, 8) |
| 34 | +#define IOMODE_SDQ FIELD_PREP(IOMODE_MASK, 3) |
| 35 | +#define MAXFREQ_MASK GENMASK(12, 10) |
| 36 | +#define MAXFREQ_33MHZ FIELD_PREP(MAXFREQ_MASK, 2) |
| 37 | + |
| 38 | +/* ESPIHINDP bit fileds */ |
| 39 | +#define AUTO_SBLD BIT(4) |
| 40 | +#define AUTO_HS1 BIT(8) |
| 41 | +#define AUTO_HS2 BIT(12) |
| 42 | +#define AUTO_HS3 BIT(16) |
| 43 | + |
| 44 | +static int npcm_host_intf_bind(struct udevice *dev) |
| 45 | +{ |
| 46 | + struct regmap *syscon; |
| 47 | + void __iomem *base; |
| 48 | + u32 ch_supp, val; |
| 49 | + u32 ioaddr; |
| 50 | + const char *type; |
| 51 | + int ret; |
| 52 | + |
| 53 | + /* Release host wait */ |
| 54 | + setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT); |
| 55 | + |
| 56 | + syscon = syscon_regmap_lookup_by_phandle(dev, "syscon"); |
| 57 | + if (IS_ERR(syscon)) { |
| 58 | + dev_err(dev, "%s: unable to get syscon, dev %s\n", __func__, dev->name); |
| 59 | + return PTR_ERR(syscon); |
| 60 | + } |
| 61 | + |
| 62 | + ioaddr = dev_read_u32_default(dev, "ioaddr", 0); |
| 63 | + if (ioaddr) |
| 64 | + regmap_write(syscon, HIFCR, ioaddr); |
| 65 | + |
| 66 | + type = dev_read_string(dev, "type"); |
| 67 | + if (!type) |
| 68 | + return -EINVAL; |
| 69 | + |
| 70 | + if (!strcmp(type, "espi")) { |
| 71 | + base = dev_read_addr_ptr(dev); |
| 72 | + if (!base) |
| 73 | + return -EINVAL; |
| 74 | + |
| 75 | + ret = dev_read_u32(dev, "channel-support", &ch_supp); |
| 76 | + if (ret) |
| 77 | + return ret; |
| 78 | + |
| 79 | + /* Select eSPI pins function */ |
| 80 | + regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, 0); |
| 81 | + regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, MFSEL4_ESPISEL); |
| 82 | + |
| 83 | + val = AUTO_SBLD | AUTO_HS1 | AUTO_HS2 | AUTO_HS3 | ch_supp; |
| 84 | + writel(val, base + ESPIHINDP); |
| 85 | + |
| 86 | + val = readl(base + ESPICFG); |
| 87 | + val &= ~(CHSUPP_MASK | IOMODE_MASK | MAXFREQ_MASK); |
| 88 | + val |= IOMODE_SDQ | MAXFREQ_33MHZ | FIELD_PREP(CHSUPP_MASK, ch_supp); |
| 89 | + writel(val, base + ESPICFG); |
| 90 | + } else if (!strcmp(type, "lpc")) { |
| 91 | + /* Select LPC pin function */ |
| 92 | + regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, 0); |
| 93 | + regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, MFSEL1_LPCSEL); |
| 94 | + } |
| 95 | + |
| 96 | + return 0; |
| 97 | +} |
| 98 | + |
| 99 | +static const struct udevice_id npcm_hostintf_ids[] = { |
| 100 | + { .compatible = "nuvoton,npcm750-host-intf" }, |
| 101 | + { .compatible = "nuvoton,npcm845-host-intf" }, |
| 102 | + { } |
| 103 | +}; |
| 104 | + |
| 105 | +U_BOOT_DRIVER(npcm_host_intf) = { |
| 106 | + .name = "npcm_host_intf", |
| 107 | + .id = UCLASS_MISC, |
| 108 | + .of_match = npcm_hostintf_ids, |
| 109 | + .bind = npcm_host_intf_bind, |
| 110 | +}; |
0 commit comments