162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2022-2023, Advanced Micro Devices, Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/pci.h>
762306a36Sopenharmony_ci#include <linux/of.h>
862306a36Sopenharmony_ci#include <linux/of_irq.h>
962306a36Sopenharmony_ci#include <linux/bitfield.h>
1062306a36Sopenharmony_ci#include <linux/bits.h>
1162306a36Sopenharmony_ci#include "pci.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define OF_PCI_ADDRESS_CELLS		3
1462306a36Sopenharmony_ci#define OF_PCI_SIZE_CELLS		2
1562306a36Sopenharmony_ci#define OF_PCI_MAX_INT_PIN		4
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct of_pci_addr_pair {
1862306a36Sopenharmony_ci	u32		phys_addr[OF_PCI_ADDRESS_CELLS];
1962306a36Sopenharmony_ci	u32		size[OF_PCI_SIZE_CELLS];
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Each entry in the ranges table is a tuple containing the child address,
2462306a36Sopenharmony_ci * the parent address, and the size of the region in the child address space.
2562306a36Sopenharmony_ci * Thus, for PCI, in each entry parent address is an address on the primary
2662306a36Sopenharmony_ci * side and the child address is the corresponding address on the secondary
2762306a36Sopenharmony_ci * side.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistruct of_pci_range {
3062306a36Sopenharmony_ci	u32		child_addr[OF_PCI_ADDRESS_CELLS];
3162306a36Sopenharmony_ci	u32		parent_addr[OF_PCI_ADDRESS_CELLS];
3262306a36Sopenharmony_ci	u32		size[OF_PCI_SIZE_CELLS];
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define OF_PCI_ADDR_SPACE_IO		0x1
3662306a36Sopenharmony_ci#define OF_PCI_ADDR_SPACE_MEM32		0x2
3762306a36Sopenharmony_ci#define OF_PCI_ADDR_SPACE_MEM64		0x3
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_NONRELOC	BIT(31)
4062306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_SS		GENMASK(25, 24)
4162306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_PREFETCH	BIT(30)
4262306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_BUS		GENMASK(23, 16)
4362306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_DEV		GENMASK(15, 11)
4462306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_FUNC		GENMASK(10, 8)
4562306a36Sopenharmony_ci#define OF_PCI_ADDR_FIELD_REG		GENMASK(7, 0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cienum of_pci_prop_compatible {
4862306a36Sopenharmony_ci	PROP_COMPAT_PCI_VVVV_DDDD,
4962306a36Sopenharmony_ci	PROP_COMPAT_PCICLASS_CCSSPP,
5062306a36Sopenharmony_ci	PROP_COMPAT_PCICLASS_CCSS,
5162306a36Sopenharmony_ci	PROP_COMPAT_NUM,
5262306a36Sopenharmony_ci};
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void of_pci_set_address(struct pci_dev *pdev, u32 *prop, u64 addr,
5562306a36Sopenharmony_ci			       u32 reg_num, u32 flags, bool reloc)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	prop[0] = FIELD_PREP(OF_PCI_ADDR_FIELD_BUS, pdev->bus->number) |
5862306a36Sopenharmony_ci		FIELD_PREP(OF_PCI_ADDR_FIELD_DEV, PCI_SLOT(pdev->devfn)) |
5962306a36Sopenharmony_ci		FIELD_PREP(OF_PCI_ADDR_FIELD_FUNC, PCI_FUNC(pdev->devfn));
6062306a36Sopenharmony_ci	prop[0] |= flags | reg_num;
6162306a36Sopenharmony_ci	if (!reloc) {
6262306a36Sopenharmony_ci		prop[0] |= OF_PCI_ADDR_FIELD_NONRELOC;
6362306a36Sopenharmony_ci		prop[1] = upper_32_bits(addr);
6462306a36Sopenharmony_ci		prop[2] = lower_32_bits(addr);
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int of_pci_get_addr_flags(struct resource *res, u32 *flags)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	u32 ss;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (res->flags & IORESOURCE_IO)
7362306a36Sopenharmony_ci		ss = OF_PCI_ADDR_SPACE_IO;
7462306a36Sopenharmony_ci	else if (res->flags & IORESOURCE_MEM_64)
7562306a36Sopenharmony_ci		ss = OF_PCI_ADDR_SPACE_MEM64;
7662306a36Sopenharmony_ci	else if (res->flags & IORESOURCE_MEM)
7762306a36Sopenharmony_ci		ss = OF_PCI_ADDR_SPACE_MEM32;
7862306a36Sopenharmony_ci	else
7962306a36Sopenharmony_ci		return -EINVAL;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	*flags = 0;
8262306a36Sopenharmony_ci	if (res->flags & IORESOURCE_PREFETCH)
8362306a36Sopenharmony_ci		*flags |= OF_PCI_ADDR_FIELD_PREFETCH;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	*flags |= FIELD_PREP(OF_PCI_ADDR_FIELD_SS, ss);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return 0;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic int of_pci_prop_bus_range(struct pci_dev *pdev,
9162306a36Sopenharmony_ci				 struct of_changeset *ocs,
9262306a36Sopenharmony_ci				 struct device_node *np)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	u32 bus_range[] = { pdev->subordinate->busn_res.start,
9562306a36Sopenharmony_ci			    pdev->subordinate->busn_res.end };
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return of_changeset_add_prop_u32_array(ocs, np, "bus-range", bus_range,
9862306a36Sopenharmony_ci					       ARRAY_SIZE(bus_range));
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int of_pci_prop_ranges(struct pci_dev *pdev, struct of_changeset *ocs,
10262306a36Sopenharmony_ci			      struct device_node *np)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	struct of_pci_range *rp;
10562306a36Sopenharmony_ci	struct resource *res;
10662306a36Sopenharmony_ci	int i, j, ret;
10762306a36Sopenharmony_ci	u32 flags, num;
10862306a36Sopenharmony_ci	u64 val64;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (pci_is_bridge(pdev)) {
11162306a36Sopenharmony_ci		num = PCI_BRIDGE_RESOURCE_NUM;
11262306a36Sopenharmony_ci		res = &pdev->resource[PCI_BRIDGE_RESOURCES];
11362306a36Sopenharmony_ci	} else {
11462306a36Sopenharmony_ci		num = PCI_STD_NUM_BARS;
11562306a36Sopenharmony_ci		res = &pdev->resource[PCI_STD_RESOURCES];
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	rp = kcalloc(num, sizeof(*rp), GFP_KERNEL);
11962306a36Sopenharmony_ci	if (!rp)
12062306a36Sopenharmony_ci		return -ENOMEM;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	for (i = 0, j = 0; j < num; j++) {
12362306a36Sopenharmony_ci		if (!resource_size(&res[j]))
12462306a36Sopenharmony_ci			continue;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci		if (of_pci_get_addr_flags(&res[j], &flags))
12762306a36Sopenharmony_ci			continue;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		val64 = res[j].start;
13062306a36Sopenharmony_ci		of_pci_set_address(pdev, rp[i].parent_addr, val64, 0, flags,
13162306a36Sopenharmony_ci				   false);
13262306a36Sopenharmony_ci		if (pci_is_bridge(pdev)) {
13362306a36Sopenharmony_ci			memcpy(rp[i].child_addr, rp[i].parent_addr,
13462306a36Sopenharmony_ci			       sizeof(rp[i].child_addr));
13562306a36Sopenharmony_ci		} else {
13662306a36Sopenharmony_ci			/*
13762306a36Sopenharmony_ci			 * For endpoint device, the lower 64-bits of child
13862306a36Sopenharmony_ci			 * address is always zero.
13962306a36Sopenharmony_ci			 */
14062306a36Sopenharmony_ci			rp[i].child_addr[0] = j;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci		val64 = resource_size(&res[j]);
14462306a36Sopenharmony_ci		rp[i].size[0] = upper_32_bits(val64);
14562306a36Sopenharmony_ci		rp[i].size[1] = lower_32_bits(val64);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		i++;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32_array(ocs, np, "ranges", (u32 *)rp,
15162306a36Sopenharmony_ci					      i * sizeof(*rp) / sizeof(u32));
15262306a36Sopenharmony_ci	kfree(rp);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	return ret;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_cistatic int of_pci_prop_reg(struct pci_dev *pdev, struct of_changeset *ocs,
15862306a36Sopenharmony_ci			   struct device_node *np)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	struct of_pci_addr_pair reg = { 0 };
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* configuration space */
16362306a36Sopenharmony_ci	of_pci_set_address(pdev, reg.phys_addr, 0, 0, 0, true);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return of_changeset_add_prop_u32_array(ocs, np, "reg", (u32 *)&reg,
16662306a36Sopenharmony_ci					       sizeof(reg) / sizeof(u32));
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistatic int of_pci_prop_interrupts(struct pci_dev *pdev,
17062306a36Sopenharmony_ci				  struct of_changeset *ocs,
17162306a36Sopenharmony_ci				  struct device_node *np)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	int ret;
17462306a36Sopenharmony_ci	u8 pin;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	ret = pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &pin);
17762306a36Sopenharmony_ci	if (ret != 0)
17862306a36Sopenharmony_ci		return ret;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	if (!pin)
18162306a36Sopenharmony_ci		return 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	return of_changeset_add_prop_u32(ocs, np, "interrupts", (u32)pin);
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cistatic int of_pci_prop_intr_map(struct pci_dev *pdev, struct of_changeset *ocs,
18762306a36Sopenharmony_ci				struct device_node *np)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	u32 i, addr_sz[OF_PCI_MAX_INT_PIN] = { 0 }, map_sz = 0;
19062306a36Sopenharmony_ci	struct of_phandle_args out_irq[OF_PCI_MAX_INT_PIN];
19162306a36Sopenharmony_ci	__be32 laddr[OF_PCI_ADDRESS_CELLS] = { 0 };
19262306a36Sopenharmony_ci	u32 int_map_mask[] = { 0xffff00, 0, 0, 7 };
19362306a36Sopenharmony_ci	struct device_node *pnode;
19462306a36Sopenharmony_ci	struct pci_dev *child;
19562306a36Sopenharmony_ci	u32 *int_map, *mapp;
19662306a36Sopenharmony_ci	int ret;
19762306a36Sopenharmony_ci	u8 pin;
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	pnode = pci_device_to_OF_node(pdev->bus->self);
20062306a36Sopenharmony_ci	if (!pnode)
20162306a36Sopenharmony_ci		pnode = pci_bus_to_OF_node(pdev->bus);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (!pnode) {
20462306a36Sopenharmony_ci		pci_err(pdev, "failed to get parent device node");
20562306a36Sopenharmony_ci		return -EINVAL;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
20962306a36Sopenharmony_ci	for (pin = 1; pin <= OF_PCI_MAX_INT_PIN;  pin++) {
21062306a36Sopenharmony_ci		i = pin - 1;
21162306a36Sopenharmony_ci		out_irq[i].np = pnode;
21262306a36Sopenharmony_ci		out_irq[i].args_count = 1;
21362306a36Sopenharmony_ci		out_irq[i].args[0] = pin;
21462306a36Sopenharmony_ci		ret = of_irq_parse_raw(laddr, &out_irq[i]);
21562306a36Sopenharmony_ci		if (ret) {
21662306a36Sopenharmony_ci			out_irq[i].np = NULL;
21762306a36Sopenharmony_ci			pci_dbg(pdev, "parse irq %d failed, ret %d", pin, ret);
21862306a36Sopenharmony_ci			continue;
21962306a36Sopenharmony_ci		}
22062306a36Sopenharmony_ci		of_property_read_u32(out_irq[i].np, "#address-cells",
22162306a36Sopenharmony_ci				     &addr_sz[i]);
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
22562306a36Sopenharmony_ci		for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) {
22662306a36Sopenharmony_ci			i = pci_swizzle_interrupt_pin(child, pin) - 1;
22762306a36Sopenharmony_ci			if (!out_irq[i].np)
22862306a36Sopenharmony_ci				continue;
22962306a36Sopenharmony_ci			map_sz += 5 + addr_sz[i] + out_irq[i].args_count;
23062306a36Sopenharmony_ci		}
23162306a36Sopenharmony_ci	}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/*
23462306a36Sopenharmony_ci	 * Parsing interrupt failed for all pins. In this case, it does not
23562306a36Sopenharmony_ci	 * need to generate interrupt-map property.
23662306a36Sopenharmony_ci	 */
23762306a36Sopenharmony_ci	if (!map_sz)
23862306a36Sopenharmony_ci		return 0;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	int_map = kcalloc(map_sz, sizeof(u32), GFP_KERNEL);
24162306a36Sopenharmony_ci	mapp = int_map;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {
24462306a36Sopenharmony_ci		for (pin = 1; pin <= OF_PCI_MAX_INT_PIN; pin++) {
24562306a36Sopenharmony_ci			i = pci_swizzle_interrupt_pin(child, pin) - 1;
24662306a36Sopenharmony_ci			if (!out_irq[i].np)
24762306a36Sopenharmony_ci				continue;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			*mapp = (child->bus->number << 16) |
25062306a36Sopenharmony_ci				(child->devfn << 8);
25162306a36Sopenharmony_ci			mapp += OF_PCI_ADDRESS_CELLS;
25262306a36Sopenharmony_ci			*mapp = pin;
25362306a36Sopenharmony_ci			mapp++;
25462306a36Sopenharmony_ci			*mapp = out_irq[i].np->phandle;
25562306a36Sopenharmony_ci			mapp++;
25662306a36Sopenharmony_ci			if (addr_sz[i]) {
25762306a36Sopenharmony_ci				ret = of_property_read_u32_array(out_irq[i].np,
25862306a36Sopenharmony_ci								 "reg", mapp,
25962306a36Sopenharmony_ci								 addr_sz[i]);
26062306a36Sopenharmony_ci				if (ret)
26162306a36Sopenharmony_ci					goto failed;
26262306a36Sopenharmony_ci			}
26362306a36Sopenharmony_ci			mapp += addr_sz[i];
26462306a36Sopenharmony_ci			memcpy(mapp, out_irq[i].args,
26562306a36Sopenharmony_ci			       out_irq[i].args_count * sizeof(u32));
26662306a36Sopenharmony_ci			mapp += out_irq[i].args_count;
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci	}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32_array(ocs, np, "interrupt-map", int_map,
27162306a36Sopenharmony_ci					      map_sz);
27262306a36Sopenharmony_ci	if (ret)
27362306a36Sopenharmony_ci		goto failed;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32(ocs, np, "#interrupt-cells", 1);
27662306a36Sopenharmony_ci	if (ret)
27762306a36Sopenharmony_ci		goto failed;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32_array(ocs, np, "interrupt-map-mask",
28062306a36Sopenharmony_ci					      int_map_mask,
28162306a36Sopenharmony_ci					      ARRAY_SIZE(int_map_mask));
28262306a36Sopenharmony_ci	if (ret)
28362306a36Sopenharmony_ci		goto failed;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	kfree(int_map);
28662306a36Sopenharmony_ci	return 0;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cifailed:
28962306a36Sopenharmony_ci	kfree(int_map);
29062306a36Sopenharmony_ci	return ret;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic int of_pci_prop_compatible(struct pci_dev *pdev,
29462306a36Sopenharmony_ci				  struct of_changeset *ocs,
29562306a36Sopenharmony_ci				  struct device_node *np)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	const char *compat_strs[PROP_COMPAT_NUM] = { 0 };
29862306a36Sopenharmony_ci	int i, ret;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	compat_strs[PROP_COMPAT_PCI_VVVV_DDDD] =
30162306a36Sopenharmony_ci		kasprintf(GFP_KERNEL, "pci%x,%x", pdev->vendor, pdev->device);
30262306a36Sopenharmony_ci	compat_strs[PROP_COMPAT_PCICLASS_CCSSPP] =
30362306a36Sopenharmony_ci		kasprintf(GFP_KERNEL, "pciclass,%06x", pdev->class);
30462306a36Sopenharmony_ci	compat_strs[PROP_COMPAT_PCICLASS_CCSS] =
30562306a36Sopenharmony_ci		kasprintf(GFP_KERNEL, "pciclass,%04x", pdev->class >> 8);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	ret = of_changeset_add_prop_string_array(ocs, np, "compatible",
30862306a36Sopenharmony_ci						 compat_strs, PROP_COMPAT_NUM);
30962306a36Sopenharmony_ci	for (i = 0; i < PROP_COMPAT_NUM; i++)
31062306a36Sopenharmony_ci		kfree(compat_strs[i]);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	return ret;
31362306a36Sopenharmony_ci}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ciint of_pci_add_properties(struct pci_dev *pdev, struct of_changeset *ocs,
31662306a36Sopenharmony_ci			  struct device_node *np)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	int ret;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/*
32162306a36Sopenharmony_ci	 * The added properties will be released when the
32262306a36Sopenharmony_ci	 * changeset is destroyed.
32362306a36Sopenharmony_ci	 */
32462306a36Sopenharmony_ci	if (pci_is_bridge(pdev)) {
32562306a36Sopenharmony_ci		ret = of_changeset_add_prop_string(ocs, np, "device_type",
32662306a36Sopenharmony_ci						   "pci");
32762306a36Sopenharmony_ci		if (ret)
32862306a36Sopenharmony_ci			return ret;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		ret = of_pci_prop_bus_range(pdev, ocs, np);
33162306a36Sopenharmony_ci		if (ret)
33262306a36Sopenharmony_ci			return ret;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		ret = of_pci_prop_intr_map(pdev, ocs, np);
33562306a36Sopenharmony_ci		if (ret)
33662306a36Sopenharmony_ci			return ret;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	ret = of_pci_prop_ranges(pdev, ocs, np);
34062306a36Sopenharmony_ci	if (ret)
34162306a36Sopenharmony_ci		return ret;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32(ocs, np, "#address-cells",
34462306a36Sopenharmony_ci					OF_PCI_ADDRESS_CELLS);
34562306a36Sopenharmony_ci	if (ret)
34662306a36Sopenharmony_ci		return ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	ret = of_changeset_add_prop_u32(ocs, np, "#size-cells",
34962306a36Sopenharmony_ci					OF_PCI_SIZE_CELLS);
35062306a36Sopenharmony_ci	if (ret)
35162306a36Sopenharmony_ci		return ret;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	ret = of_pci_prop_reg(pdev, ocs, np);
35462306a36Sopenharmony_ci	if (ret)
35562306a36Sopenharmony_ci		return ret;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	ret = of_pci_prop_compatible(pdev, ocs, np);
35862306a36Sopenharmony_ci	if (ret)
35962306a36Sopenharmony_ci		return ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	ret = of_pci_prop_interrupts(pdev, ocs, np);
36262306a36Sopenharmony_ci	if (ret)
36362306a36Sopenharmony_ci		return ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
367