Jim Liu | cce4eed | 2022-06-24 16:24:37 +0800 | [diff] [blame] | 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 | }; |