162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PowerNV LPC bus handling.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2013 IBM Corp.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/kernel.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/bug.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/debugfs.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/machdep.h>
1662306a36Sopenharmony_ci#include <asm/firmware.h>
1762306a36Sopenharmony_ci#include <asm/opal.h>
1862306a36Sopenharmony_ci#include <asm/prom.h>
1962306a36Sopenharmony_ci#include <linux/uaccess.h>
2062306a36Sopenharmony_ci#include <asm/isa-bridge.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int opal_lpc_chip_id = -1;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic u8 opal_lpc_inb(unsigned long port)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	int64_t rc;
2762306a36Sopenharmony_ci	__be32 data;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xffff)
3062306a36Sopenharmony_ci		return 0xff;
3162306a36Sopenharmony_ci	rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 1);
3262306a36Sopenharmony_ci	return rc ? 0xff : be32_to_cpu(data);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic __le16 __opal_lpc_inw(unsigned long port)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	int64_t rc;
3862306a36Sopenharmony_ci	__be32 data;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xfffe)
4162306a36Sopenharmony_ci		return 0xffff;
4262306a36Sopenharmony_ci	if (port & 1)
4362306a36Sopenharmony_ci		return (__le16)opal_lpc_inb(port) << 8 | opal_lpc_inb(port + 1);
4462306a36Sopenharmony_ci	rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 2);
4562306a36Sopenharmony_ci	return rc ? 0xffff : be32_to_cpu(data);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_cistatic u16 opal_lpc_inw(unsigned long port)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	return le16_to_cpu(__opal_lpc_inw(port));
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic __le32 __opal_lpc_inl(unsigned long port)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	int64_t rc;
5562306a36Sopenharmony_ci	__be32 data;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xfffc)
5862306a36Sopenharmony_ci		return 0xffffffff;
5962306a36Sopenharmony_ci	if (port & 3)
6062306a36Sopenharmony_ci		return (__le32)opal_lpc_inb(port    ) << 24 |
6162306a36Sopenharmony_ci		       (__le32)opal_lpc_inb(port + 1) << 16 |
6262306a36Sopenharmony_ci		       (__le32)opal_lpc_inb(port + 2) <<  8 |
6362306a36Sopenharmony_ci			       opal_lpc_inb(port + 3);
6462306a36Sopenharmony_ci	rc = opal_lpc_read(opal_lpc_chip_id, OPAL_LPC_IO, port, &data, 4);
6562306a36Sopenharmony_ci	return rc ? 0xffffffff : be32_to_cpu(data);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic u32 opal_lpc_inl(unsigned long port)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return le32_to_cpu(__opal_lpc_inl(port));
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic void opal_lpc_outb(u8 val, unsigned long port)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xffff)
7662306a36Sopenharmony_ci		return;
7762306a36Sopenharmony_ci	opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 1);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic void __opal_lpc_outw(__le16 val, unsigned long port)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xfffe)
8362306a36Sopenharmony_ci		return;
8462306a36Sopenharmony_ci	if (port & 1) {
8562306a36Sopenharmony_ci		opal_lpc_outb(val >> 8, port);
8662306a36Sopenharmony_ci		opal_lpc_outb(val     , port + 1);
8762306a36Sopenharmony_ci		return;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci	opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 2);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistatic void opal_lpc_outw(u16 val, unsigned long port)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	__opal_lpc_outw(cpu_to_le16(val), port);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic void __opal_lpc_outl(__le32 val, unsigned long port)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0 || port > 0xfffc)
10062306a36Sopenharmony_ci		return;
10162306a36Sopenharmony_ci	if (port & 3) {
10262306a36Sopenharmony_ci		opal_lpc_outb(val >> 24, port);
10362306a36Sopenharmony_ci		opal_lpc_outb(val >> 16, port + 1);
10462306a36Sopenharmony_ci		opal_lpc_outb(val >>  8, port + 2);
10562306a36Sopenharmony_ci		opal_lpc_outb(val      , port + 3);
10662306a36Sopenharmony_ci		return;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci	opal_lpc_write(opal_lpc_chip_id, OPAL_LPC_IO, port, val, 4);
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void opal_lpc_outl(u32 val, unsigned long port)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	__opal_lpc_outl(cpu_to_le32(val), port);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void opal_lpc_insb(unsigned long p, void *b, unsigned long c)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	u8 *ptr = b;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	while(c--)
12162306a36Sopenharmony_ci		*(ptr++) = opal_lpc_inb(p);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void opal_lpc_insw(unsigned long p, void *b, unsigned long c)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	__le16 *ptr = b;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	while(c--)
12962306a36Sopenharmony_ci		*(ptr++) = __opal_lpc_inw(p);
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic void opal_lpc_insl(unsigned long p, void *b, unsigned long c)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	__le32 *ptr = b;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	while(c--)
13762306a36Sopenharmony_ci		*(ptr++) = __opal_lpc_inl(p);
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic void opal_lpc_outsb(unsigned long p, const void *b, unsigned long c)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	const u8 *ptr = b;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	while(c--)
14562306a36Sopenharmony_ci		opal_lpc_outb(*(ptr++), p);
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void opal_lpc_outsw(unsigned long p, const void *b, unsigned long c)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	const __le16 *ptr = b;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	while(c--)
15362306a36Sopenharmony_ci		__opal_lpc_outw(*(ptr++), p);
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void opal_lpc_outsl(unsigned long p, const void *b, unsigned long c)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	const __le32 *ptr = b;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	while(c--)
16162306a36Sopenharmony_ci		__opal_lpc_outl(*(ptr++), p);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic const struct ppc_pci_io opal_lpc_io = {
16562306a36Sopenharmony_ci	.inb	= opal_lpc_inb,
16662306a36Sopenharmony_ci	.inw	= opal_lpc_inw,
16762306a36Sopenharmony_ci	.inl	= opal_lpc_inl,
16862306a36Sopenharmony_ci	.outb	= opal_lpc_outb,
16962306a36Sopenharmony_ci	.outw	= opal_lpc_outw,
17062306a36Sopenharmony_ci	.outl	= opal_lpc_outl,
17162306a36Sopenharmony_ci	.insb	= opal_lpc_insb,
17262306a36Sopenharmony_ci	.insw	= opal_lpc_insw,
17362306a36Sopenharmony_ci	.insl	= opal_lpc_insl,
17462306a36Sopenharmony_ci	.outsb	= opal_lpc_outsb,
17562306a36Sopenharmony_ci	.outsw	= opal_lpc_outsw,
17662306a36Sopenharmony_ci	.outsl	= opal_lpc_outsl,
17762306a36Sopenharmony_ci};
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
18062306a36Sopenharmony_cistruct lpc_debugfs_entry {
18162306a36Sopenharmony_ci	enum OpalLPCAddressType lpc_type;
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic ssize_t lpc_debug_read(struct file *filp, char __user *ubuf,
18562306a36Sopenharmony_ci			      size_t count, loff_t *ppos)
18662306a36Sopenharmony_ci{
18762306a36Sopenharmony_ci	struct lpc_debugfs_entry *lpc = filp->private_data;
18862306a36Sopenharmony_ci	u32 data, pos, len, todo;
18962306a36Sopenharmony_ci	int rc;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	if (!access_ok(ubuf, count))
19262306a36Sopenharmony_ci		return -EFAULT;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	todo = count;
19562306a36Sopenharmony_ci	while (todo) {
19662306a36Sopenharmony_ci		pos = *ppos;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		/*
19962306a36Sopenharmony_ci		 * Select access size based on count and alignment and
20062306a36Sopenharmony_ci		 * access type. IO and MEM only support byte accesses,
20162306a36Sopenharmony_ci		 * FW supports all 3.
20262306a36Sopenharmony_ci		 */
20362306a36Sopenharmony_ci		len = 1;
20462306a36Sopenharmony_ci		if (lpc->lpc_type == OPAL_LPC_FW) {
20562306a36Sopenharmony_ci			if (todo > 3 && (pos & 3) == 0)
20662306a36Sopenharmony_ci				len = 4;
20762306a36Sopenharmony_ci			else if (todo > 1 && (pos & 1) == 0)
20862306a36Sopenharmony_ci				len = 2;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci		rc = opal_lpc_read(opal_lpc_chip_id, lpc->lpc_type, pos,
21162306a36Sopenharmony_ci				   &data, len);
21262306a36Sopenharmony_ci		if (rc)
21362306a36Sopenharmony_ci			return -ENXIO;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		/*
21662306a36Sopenharmony_ci		 * Now there is some trickery with the data returned by OPAL
21762306a36Sopenharmony_ci		 * as it's the desired data right justified in a 32-bit BE
21862306a36Sopenharmony_ci		 * word.
21962306a36Sopenharmony_ci		 *
22062306a36Sopenharmony_ci		 * This is a very bad interface and I'm to blame for it :-(
22162306a36Sopenharmony_ci		 *
22262306a36Sopenharmony_ci		 * So we can't just apply a 32-bit swap to what comes from OPAL,
22362306a36Sopenharmony_ci		 * because user space expects the *bytes* to be in their proper
22462306a36Sopenharmony_ci		 * respective positions (ie, LPC position).
22562306a36Sopenharmony_ci		 *
22662306a36Sopenharmony_ci		 * So what we really want to do here is to shift data right
22762306a36Sopenharmony_ci		 * appropriately on a LE kernel.
22862306a36Sopenharmony_ci		 *
22962306a36Sopenharmony_ci		 * IE. If the LPC transaction has bytes B0, B1, B2 and B3 in that
23062306a36Sopenharmony_ci		 * order, we have in memory written to by OPAL at the "data"
23162306a36Sopenharmony_ci		 * pointer:
23262306a36Sopenharmony_ci		 *
23362306a36Sopenharmony_ci		 *               Bytes:      OPAL "data"   LE "data"
23462306a36Sopenharmony_ci		 *   32-bit:   B0 B1 B2 B3   B0B1B2B3      B3B2B1B0
23562306a36Sopenharmony_ci		 *   16-bit:   B0 B1         0000B0B1      B1B00000
23662306a36Sopenharmony_ci		 *    8-bit:   B0            000000B0      B0000000
23762306a36Sopenharmony_ci		 *
23862306a36Sopenharmony_ci		 * So a BE kernel will have the leftmost of the above in the MSB
23962306a36Sopenharmony_ci		 * and rightmost in the LSB and can just then "cast" the u32 "data"
24062306a36Sopenharmony_ci		 * down to the appropriate quantity and write it.
24162306a36Sopenharmony_ci		 *
24262306a36Sopenharmony_ci		 * However, an LE kernel can't. It doesn't need to swap because a
24362306a36Sopenharmony_ci		 * load from data followed by a store to user are going to preserve
24462306a36Sopenharmony_ci		 * the byte ordering which is the wire byte order which is what the
24562306a36Sopenharmony_ci		 * user wants, but in order to "crop" to the right size, we need to
24662306a36Sopenharmony_ci		 * shift right first.
24762306a36Sopenharmony_ci		 */
24862306a36Sopenharmony_ci		switch(len) {
24962306a36Sopenharmony_ci		case 4:
25062306a36Sopenharmony_ci			rc = __put_user((u32)data, (u32 __user *)ubuf);
25162306a36Sopenharmony_ci			break;
25262306a36Sopenharmony_ci		case 2:
25362306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
25462306a36Sopenharmony_ci			data >>= 16;
25562306a36Sopenharmony_ci#endif
25662306a36Sopenharmony_ci			rc = __put_user((u16)data, (u16 __user *)ubuf);
25762306a36Sopenharmony_ci			break;
25862306a36Sopenharmony_ci		default:
25962306a36Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
26062306a36Sopenharmony_ci			data >>= 24;
26162306a36Sopenharmony_ci#endif
26262306a36Sopenharmony_ci			rc = __put_user((u8)data, (u8 __user *)ubuf);
26362306a36Sopenharmony_ci			break;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci		if (rc)
26662306a36Sopenharmony_ci			return -EFAULT;
26762306a36Sopenharmony_ci		*ppos += len;
26862306a36Sopenharmony_ci		ubuf += len;
26962306a36Sopenharmony_ci		todo -= len;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return count;
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cistatic ssize_t lpc_debug_write(struct file *filp, const char __user *ubuf,
27662306a36Sopenharmony_ci			       size_t count, loff_t *ppos)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	struct lpc_debugfs_entry *lpc = filp->private_data;
27962306a36Sopenharmony_ci	u32 data, pos, len, todo;
28062306a36Sopenharmony_ci	int rc;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (!access_ok(ubuf, count))
28362306a36Sopenharmony_ci		return -EFAULT;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	todo = count;
28662306a36Sopenharmony_ci	while (todo) {
28762306a36Sopenharmony_ci		pos = *ppos;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		/*
29062306a36Sopenharmony_ci		 * Select access size based on count and alignment and
29162306a36Sopenharmony_ci		 * access type. IO and MEM only support byte acceses,
29262306a36Sopenharmony_ci		 * FW supports all 3.
29362306a36Sopenharmony_ci		 */
29462306a36Sopenharmony_ci		len = 1;
29562306a36Sopenharmony_ci		if (lpc->lpc_type == OPAL_LPC_FW) {
29662306a36Sopenharmony_ci			if (todo > 3 && (pos & 3) == 0)
29762306a36Sopenharmony_ci				len = 4;
29862306a36Sopenharmony_ci			else if (todo > 1 && (pos & 1) == 0)
29962306a36Sopenharmony_ci				len = 2;
30062306a36Sopenharmony_ci		}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci		/*
30362306a36Sopenharmony_ci		 * Similarly to the read case, we have some trickery here but
30462306a36Sopenharmony_ci		 * it's different to handle. We need to pass the value to OPAL in
30562306a36Sopenharmony_ci		 * a register whose layout depends on the access size. We want
30662306a36Sopenharmony_ci		 * to reproduce the memory layout of the user, however we aren't
30762306a36Sopenharmony_ci		 * doing a load from user and a store to another memory location
30862306a36Sopenharmony_ci		 * which would achieve that. Here we pass the value to OPAL via
30962306a36Sopenharmony_ci		 * a register which is expected to contain the "BE" interpretation
31062306a36Sopenharmony_ci		 * of the byte sequence. IE: for a 32-bit access, byte 0 should be
31162306a36Sopenharmony_ci		 * in the MSB. So here we *do* need to byteswap on LE.
31262306a36Sopenharmony_ci		 *
31362306a36Sopenharmony_ci		 *           User bytes:    LE "data"  OPAL "data"
31462306a36Sopenharmony_ci		 *  32-bit:  B0 B1 B2 B3    B3B2B1B0   B0B1B2B3
31562306a36Sopenharmony_ci		 *  16-bit:  B0 B1          0000B1B0   0000B0B1
31662306a36Sopenharmony_ci		 *   8-bit:  B0             000000B0   000000B0
31762306a36Sopenharmony_ci		 */
31862306a36Sopenharmony_ci		switch(len) {
31962306a36Sopenharmony_ci		case 4:
32062306a36Sopenharmony_ci			rc = __get_user(data, (u32 __user *)ubuf);
32162306a36Sopenharmony_ci			data = cpu_to_be32(data);
32262306a36Sopenharmony_ci			break;
32362306a36Sopenharmony_ci		case 2:
32462306a36Sopenharmony_ci			rc = __get_user(data, (u16 __user *)ubuf);
32562306a36Sopenharmony_ci			data = cpu_to_be16(data);
32662306a36Sopenharmony_ci			break;
32762306a36Sopenharmony_ci		default:
32862306a36Sopenharmony_ci			rc = __get_user(data, (u8 __user *)ubuf);
32962306a36Sopenharmony_ci			break;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci		if (rc)
33262306a36Sopenharmony_ci			return -EFAULT;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		rc = opal_lpc_write(opal_lpc_chip_id, lpc->lpc_type, pos,
33562306a36Sopenharmony_ci				    data, len);
33662306a36Sopenharmony_ci		if (rc)
33762306a36Sopenharmony_ci			return -ENXIO;
33862306a36Sopenharmony_ci		*ppos += len;
33962306a36Sopenharmony_ci		ubuf += len;
34062306a36Sopenharmony_ci		todo -= len;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return count;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic const struct file_operations lpc_fops = {
34762306a36Sopenharmony_ci	.read =		lpc_debug_read,
34862306a36Sopenharmony_ci	.write =	lpc_debug_write,
34962306a36Sopenharmony_ci	.open =		simple_open,
35062306a36Sopenharmony_ci	.llseek =	default_llseek,
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int opal_lpc_debugfs_create_type(struct dentry *folder,
35462306a36Sopenharmony_ci					const char *fname,
35562306a36Sopenharmony_ci					enum OpalLPCAddressType type)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct lpc_debugfs_entry *entry;
35862306a36Sopenharmony_ci	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
35962306a36Sopenharmony_ci	if (!entry)
36062306a36Sopenharmony_ci		return -ENOMEM;
36162306a36Sopenharmony_ci	entry->lpc_type = type;
36262306a36Sopenharmony_ci	debugfs_create_file(fname, 0600, folder, entry, &lpc_fops);
36362306a36Sopenharmony_ci	return 0;
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic int opal_lpc_init_debugfs(void)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	struct dentry *root;
36962306a36Sopenharmony_ci	int rc = 0;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0)
37262306a36Sopenharmony_ci		return -ENODEV;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	root = debugfs_create_dir("lpc", arch_debugfs_dir);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	rc |= opal_lpc_debugfs_create_type(root, "io", OPAL_LPC_IO);
37762306a36Sopenharmony_ci	rc |= opal_lpc_debugfs_create_type(root, "mem", OPAL_LPC_MEM);
37862306a36Sopenharmony_ci	rc |= opal_lpc_debugfs_create_type(root, "fw", OPAL_LPC_FW);
37962306a36Sopenharmony_ci	return rc;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_cimachine_device_initcall(powernv, opal_lpc_init_debugfs);
38262306a36Sopenharmony_ci#endif  /* CONFIG_DEBUG_FS */
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_civoid __init opal_lpc_init(void)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct device_node *np;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	/*
38962306a36Sopenharmony_ci	 * Look for a Power8 LPC bus tagged as "primary",
39062306a36Sopenharmony_ci	 * we currently support only one though the OPAL APIs
39162306a36Sopenharmony_ci	 * support any number.
39262306a36Sopenharmony_ci	 */
39362306a36Sopenharmony_ci	for_each_compatible_node(np, NULL, "ibm,power8-lpc") {
39462306a36Sopenharmony_ci		if (!of_device_is_available(np))
39562306a36Sopenharmony_ci			continue;
39662306a36Sopenharmony_ci		if (!of_get_property(np, "primary", NULL))
39762306a36Sopenharmony_ci			continue;
39862306a36Sopenharmony_ci		opal_lpc_chip_id = of_get_ibm_chip_id(np);
39962306a36Sopenharmony_ci		of_node_put(np);
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci	if (opal_lpc_chip_id < 0)
40362306a36Sopenharmony_ci		return;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* Does it support direct mapping ? */
40662306a36Sopenharmony_ci	if (of_property_present(np, "ranges")) {
40762306a36Sopenharmony_ci		pr_info("OPAL: Found memory mapped LPC bus on chip %d\n",
40862306a36Sopenharmony_ci			opal_lpc_chip_id);
40962306a36Sopenharmony_ci		isa_bridge_init_non_pci(np);
41062306a36Sopenharmony_ci	} else {
41162306a36Sopenharmony_ci		pr_info("OPAL: Found non-mapped LPC bus on chip %d\n",
41262306a36Sopenharmony_ci			opal_lpc_chip_id);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci		/* Setup special IO ops */
41562306a36Sopenharmony_ci		ppc_pci_io = opal_lpc_io;
41662306a36Sopenharmony_ci		isa_io_special = true;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci}
419