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