misc: nuvoton: Add host interface configuration driver
[platform/kernel/u-boot.git] / drivers / misc / npcm_host_intf.c
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 };