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
43static 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
98static const struct udevice_id npcm_hostintf_ids[] = {
99	{ .compatible = "nuvoton,npcm750-host-intf" },
100	{ .compatible = "nuvoton,npcm845-host-intf" },
101	{ }
102};
103
104U_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