]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
pci: serial: Support reading PCI-register size with base
authorSimon Glass <sjg@chromium.org>
Tue, 26 Sep 2023 14:14:58 +0000 (08:14 -0600)
committerTom Rini <trini@konsulko.com>
Fri, 6 Oct 2023 18:38:13 +0000 (14:38 -0400)
The PCI helpers read only the base address for a PCI region. In some cases
the size is needed as well, e.g. to pass along to a driver which needs to
know the size of its register area.

Update the functions to allow the size to be returned. For serial, record
the information and provided it with the serial_info() call.

A limitation still exists in that the size is not available when OF_LIVE
is enabled, so take account of that in the tests.

Signed-off-by: Simon Glass <sjg@chromium.org>
16 files changed:
arch/sandbox/dts/test.dts
drivers/core/fdtaddr.c
drivers/core/ofnode.c
drivers/core/read.c
drivers/core/util.c
drivers/pci/pci-uclass.c
drivers/pci/pci_mvebu.c
drivers/pci/pci_tegra.c
drivers/pci/pcie_mediatek.c
drivers/serial/ns16550.c
include/dm/fdtaddr.h
include/dm/ofnode.h
include/dm/read.h
include/ns16550.h
include/serial.h
test/dm/pci.c

index 962b9ebcbf65e1741ea41305f2bb096d007f8128..6abce9e3963025c2b9058ea5a0a3c473482d67c4 100644 (file)
                pci@1,0 {
                        compatible = "pci-generic";
                        /* reg 0 is at 0x14, using FDT_PCI_SPACE_MEM32 */
-                       reg = <0x02000814 0 0 0 0
-                              0x01000810 0 0 0 0>;
+                       reg = <0x02000814 0 0 0x80 0
+                              0x01000810 0 0 0xc0 0>;
                        sandbox,emul = <&swap_case_emul0_1>;
                };
                p2sb-pci@2,0 {
                pci@1f,0 {
                        compatible = "pci-generic";
                        /* reg 0 is at 0x10, using FDT_PCI_SPACE_IO */
-                       reg = <0x0100f810 0 0 0 0>;
+                       reg = <0x0100f810 0 0 0x100 0>;
                        sandbox,emul = <&swap_case_emul0_1f>;
                };
        };
index 546db675aaf611b44315da57ba5f8e6bd8318bba..b79d138c41961420f6e33912b16ea3bf3389f632 100644 (file)
@@ -215,7 +215,7 @@ void *devfdt_map_physmem(const struct udevice *dev, unsigned long size)
        return map_physmem(addr, size, MAP_NOCACHE);
 }
 
-fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
+fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
 {
        ulong addr;
 
@@ -226,12 +226,12 @@ fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev)
                int ret;
 
                ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_MEM32,
-                                          "reg", &pci_addr);
+                                          "reg", &pci_addr, sizep);
                if (ret) {
                        /* try if there is any i/o-mapped register */
                        ret = ofnode_read_pci_addr(dev_ofnode(dev),
                                                   FDT_PCI_SPACE_IO, "reg",
-                                                  &pci_addr);
+                                                  &pci_addr, sizep);
                        if (ret)
                                return FDT_ADDR_T_NONE;
                }
index 18d2eb0f1186327f0e4e03d93d807ab26c6470ba..29a429451020df72b4fb2d14b0ba2534f62eadad 100644 (file)
@@ -1270,7 +1270,8 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
 }
 
 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
-                        const char *propname, struct fdt_pci_addr *addr)
+                        const char *propname, struct fdt_pci_addr *addr,
+                        fdt_size_t *size)
 {
        const fdt32_t *cell;
        int len;
@@ -1298,14 +1299,18 @@ int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
                              (ulong)fdt32_to_cpu(cell[1]),
                              (ulong)fdt32_to_cpu(cell[2]));
                        if ((fdt32_to_cpu(*cell) & type) == type) {
+                               const unaligned_fdt64_t *ptr;
+
                                addr->phys_hi = fdt32_to_cpu(cell[0]);
                                addr->phys_mid = fdt32_to_cpu(cell[1]);
                                addr->phys_lo = fdt32_to_cpu(cell[2]);
+                               ptr = (const unaligned_fdt64_t *)(cell + 3);
+                               if (size)
+                                       *size = fdt64_to_cpu(*ptr);
                                break;
                        }
 
-                       cell += (FDT_PCI_ADDR_CELLS +
-                                FDT_PCI_SIZE_CELLS);
+                       cell += FDT_PCI_ADDR_CELLS + FDT_PCI_SIZE_CELLS;
                }
 
                if (i == num) {
index 49066b59cdaf461dda00d8b412dfcc526d319a13..419013451f0c61fde1aa0306a8691bd77b6f6d3a 100644 (file)
@@ -405,13 +405,15 @@ int dev_read_alias_highest_id(const char *stem)
        return fdtdec_get_alias_highest_id(gd->fdt_blob, stem);
 }
 
-fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
+fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep)
 {
        ulong addr;
 
        addr = dev_read_addr(dev);
+       if (sizep)
+               *sizep = 0;
        if (addr == FDT_ADDR_T_NONE && !of_live_active())
-               addr = devfdt_get_addr_pci(dev);
+               addr = devfdt_get_addr_pci(dev, sizep);
 
        return addr;
 }
index aa60fdd15bc4b1ed9ba55c013f234d9caf5a3b2c..81497df85ffd191c54026ead92cb907f24a4bfc9 100644 (file)
@@ -30,7 +30,7 @@ int pci_get_devfn(struct udevice *dev)
 
        /* Extract the devfn from fdt_pci_addr */
        ret = ofnode_read_pci_addr(dev_ofnode(dev), FDT_PCI_SPACE_CONFIG,
-                                  "reg", &addr);
+                                  "reg", &addr, NULL);
        if (ret) {
                if (ret != -ENOENT)
                        return -EINVAL;
index ae7350aaff98deea94fd9cc714bd1f4e256dd07b..e0d01f6a85db8cc6fa40fe9370863ac48a2b6b73 100644 (file)
@@ -123,7 +123,7 @@ static void pci_dev_find_ofnode(struct udevice *bus, phys_addr_t bdf,
 
        dev_for_each_subnode(node, bus) {
                ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg",
-                                          &addr);
+                                          &addr, NULL);
                if (ret)
                        continue;
 
index 3697cd8d65210be7d835040f0bdf33e5bc88ac7e..83559550e6fbe8e8a176c49dbacb6b4a12c340a2 100644 (file)
@@ -641,7 +641,8 @@ static int mvebu_pcie_port_parse_dt(ofnode node, ofnode parent, struct mvebu_pci
                pcie->is_x4 = true;
 
        /* devfn is in bits [15:8], see PCI_DEV usage */
-       ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr);
+       ret = ofnode_read_pci_addr(node, FDT_PCI_SPACE_CONFIG, "reg", &pci_addr,
+                                  NULL);
        if (ret < 0) {
                printf("%s: property \"reg\" is invalid\n", pcie->name);
                goto err;
index 131c21b7684ed89f2768a1018e722e939913b53a..d6374a58e330a4d38778acbb1f8961489a889f01 100644 (file)
@@ -462,7 +462,7 @@ static int tegra_pcie_parse_port_info(ofnode node, uint *index, uint *lanes)
 
        *lanes = err;
 
-       err = ofnode_read_pci_addr(node, 0, "reg", &addr);
+       err = ofnode_read_pci_addr(node, 0, "reg", &addr, NULL);
        if (err < 0) {
                pr_err("failed to parse \"reg\" property\n");
                return err;
index ed25a10bcf0f32715701b9a42fd3b547bc9949a5..f0f34b5d119702920f5153e3905845c21478127e 100644 (file)
@@ -661,7 +661,7 @@ static int mtk_pcie_probe(struct udevice *dev)
                if (!ofnode_is_enabled(subnode))
                        continue;
 
-               err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+               err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
                if (err)
                        return err;
 
@@ -700,7 +700,7 @@ static int mtk_pcie_probe_v2(struct udevice *dev)
                if (!ofnode_is_enabled(subnode))
                        continue;
 
-               err = ofnode_read_pci_addr(subnode, 0, "reg", &addr);
+               err = ofnode_read_pci_addr(subnode, 0, "reg", &addr, NULL);
                if (err)
                        return err;
 
index 5ca2828ae8536999d565294b970447b456b3da8b..6deb1d8ddc56c59ebda43de19500deaf2e023058 100644 (file)
@@ -484,6 +484,7 @@ static int ns16550_serial_getinfo(struct udevice *dev,
        info->addr_space = SERIAL_ADDRESS_SPACE_MEMORY;
 #endif
        info->addr = plat->base;
+       info->size = plat->size;
        info->reg_width = plat->reg_width;
        info->reg_shift = plat->reg_shift;
        info->reg_offset = plat->reg_offset;
@@ -492,7 +493,8 @@ static int ns16550_serial_getinfo(struct udevice *dev,
        return 0;
 }
 
-static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base)
+static int ns16550_serial_assign_base(struct ns16550_plat *plat,
+                                     fdt_addr_t base, fdt_size_t size)
 {
        if (base == FDT_ADDR_T_NONE)
                return -EINVAL;
@@ -502,6 +504,7 @@ static int ns16550_serial_assign_base(struct ns16550_plat *plat, fdt_addr_t base
 #else
        plat->base = (unsigned long)map_physmem(base, 0, MAP_NOCACHE);
 #endif
+       plat->size = size;
 
        return 0;
 }
@@ -512,6 +515,7 @@ int ns16550_serial_probe(struct udevice *dev)
        struct ns16550 *const com_port = dev_get_priv(dev);
        struct reset_ctl_bulk reset_bulk;
        fdt_addr_t addr;
+       fdt_addr_t size;
        int ret;
 
        /*
@@ -519,8 +523,8 @@ int ns16550_serial_probe(struct udevice *dev)
         * or via a PCI bridge, assign plat->base before probing hardware.
         */
        if (device_is_on_pci_bus(dev)) {
-               addr = devfdt_get_addr_pci(dev);
-               ret = ns16550_serial_assign_base(plat, addr);
+               addr = devfdt_get_addr_pci(dev, &size);
+               ret = ns16550_serial_assign_base(plat, addr, size);
                if (ret)
                        return ret;
        }
@@ -547,12 +551,14 @@ int ns16550_serial_of_to_plat(struct udevice *dev)
 {
        struct ns16550_plat *plat = dev_get_plat(dev);
        const u32 port_type = dev_get_driver_data(dev);
+       fdt_size_t size = 0;
        fdt_addr_t addr;
        struct clk clk;
        int err;
 
-       addr = dev_read_addr(dev);
-       err = ns16550_serial_assign_base(plat, addr);
+       addr = spl_in_proper() ? dev_read_addr_size(dev, &size) :
+               dev_read_addr(dev);
+       err = ns16550_serial_assign_base(plat, addr, size);
        if (err && !device_is_on_pci_bus(dev))
                return err;
 
index dcdc19137cc936d1a0e3864f80cf7bde856fc0e1..6d2fa8f1044b98bce3d106c61a7806abc842f3ed 100644 (file)
@@ -168,8 +168,9 @@ fdt_addr_t devfdt_get_addr_size_name(const struct udevice *dev,
  * devfdt_get_addr_pci() - Read an address and handle PCI address translation
  *
  * @dev: Device to read from
+ * @sizep: If non-NULL, returns size of address space
  * Return: address or FDT_ADDR_T_NONE if not found
  */
-fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev);
+fdt_addr_t devfdt_get_addr_pci(const struct udevice *dev, fdt_size_t *sizep);
 
 #endif
index ef1437cc556231b1faa7544f09d0a77786b1dd4b..19e97a903270e80f3b8599eb574531fd50935e06 100644 (file)
@@ -1153,13 +1153,15 @@ const uint8_t *ofnode_read_u8_array_ptr(ofnode node, const char *propname,
  * @type:      pci address type (FDT_PCI_SPACE_xxx)
  * @propname:  name of property to find
  * @addr:      returns pci address in the form of fdt_pci_addr
+ * @size:      if non-null, returns register-space size
  * Return:
  * 0 if ok, -ENOENT if the property did not exist, -EINVAL if the
  * format of the property was invalid, -ENXIO if the requested
  * address type was not found
  */
 int ofnode_read_pci_addr(ofnode node, enum fdt_pci_space type,
-                        const char *propname, struct fdt_pci_addr *addr);
+                        const char *propname, struct fdt_pci_addr *addr,
+                        fdt_size_t *size);
 
 /**
  * ofnode_read_pci_vendev() - look up PCI vendor and device id
index c2615f72f4059b975994ba081f0138b8c7a87a0e..3c2eea6f0c4b3679c13274f55f0e992b1f48b0ec 100644 (file)
@@ -346,9 +346,10 @@ void *dev_read_addr_ptr(const struct udevice *dev);
  *    fdtdec_get_addr() and friends.
  *
  * @dev: Device to read from
+ * @sizep: If non-NULL, returns size of address space found
  * Return: address or FDT_ADDR_T_NONE if not found
  */
-fdt_addr_t dev_read_addr_pci(const struct udevice *dev);
+fdt_addr_t dev_read_addr_pci(const struct udevice *dev, fdt_size_t *sizep);
 
 /**
  * dev_remap_addr() - Get the reg property of a device as a
@@ -996,9 +997,10 @@ static inline void *dev_read_addr_ptr(const struct udevice *dev)
        return devfdt_get_addr_ptr(dev);
 }
 
-static inline fdt_addr_t dev_read_addr_pci(const struct udevice *dev)
+static inline fdt_addr_t dev_read_addr_pci(const struct udevice *dev,
+                                          fdt_size_t *sizep)
 {
-       return devfdt_get_addr_pci(dev);
+       return devfdt_get_addr_pci(dev, sizep);
 }
 
 static inline void *dev_remap_addr(const struct udevice *dev)
index e7e68663d0300b73b0929ca38e92daca08524356..7f481300083ac84cf93ffc2e599c991a3fea1126 100644 (file)
@@ -58,6 +58,7 @@ enum ns16550_flags {
  * struct ns16550_plat - information about a NS16550 port
  *
  * @base:              Base register address
+ * @size:              Size of register area in bytes
  * @reg_width:         IO accesses size of registers (in bytes, 1 or 4)
  * @reg_shift:         Shift size of registers (0=byte, 1=16bit, 2=32bit...)
  * @reg_offset:                Offset to start of registers (normally 0)
@@ -67,7 +68,8 @@ enum ns16550_flags {
  * @bdf:               PCI slot/function (pci_dev_t)
  */
 struct ns16550_plat {
-       unsigned long base;
+       ulong base;
+       ulong size;
        int reg_width;
        int reg_shift;
        int reg_offset;
index 42bdf3759c00b523c3a7a50fd3f3ecf56e6ea3a9..205889d28be967681f2e1a62ead54b56205458d4 100644 (file)
@@ -137,6 +137,7 @@ enum adr_space_type {
  * @type:      type of the UART chip
  * @addr_space:        address space to access the registers
  * @addr:      physical address of the registers
+ * @size:      size of the register area in bytes
  * @reg_width: size (in bytes) of the IO accesses to the registers
  * @reg_offset:        offset to apply to the @addr from the start of the registers
  * @reg_shift: quantity to shift the register offsets by
@@ -147,6 +148,7 @@ struct serial_device_info {
        enum serial_chip_type type;
        enum adr_space_type addr_space;
        ulong addr;
+       ulong size;
        u8 reg_width;
        u8 reg_offset;
        u8 reg_shift;
index 70a736cfdb8abd63bcfe96f9cae7ddf4ed5c31aa..8c5e7da9e62906a4ea39e084b1dbd1880adad559 100644 (file)
@@ -301,10 +301,12 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts)
 {
        struct udevice *swap1f, *swap1;
        ulong io_addr, mem_addr;
+       fdt_addr_t size;
 
        ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
        io_addr = dm_pci_read_bar32(swap1f, 0);
-       ut_asserteq(io_addr, dev_read_addr_pci(swap1f));
+       ut_asserteq(io_addr, dev_read_addr_pci(swap1f, &size));
+       ut_asserteq(0, size);
 
        /*
         * This device has both I/O and MEM spaces but the MEM space appears
@@ -312,7 +314,8 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts)
         */
        ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
        mem_addr = dm_pci_read_bar32(swap1, 1);
-       ut_asserteq(mem_addr, dev_read_addr_pci(swap1));
+       ut_asserteq(mem_addr, dev_read_addr_pci(swap1, &size));
+       ut_asserteq(0, size);
 
        return 0;
 }
@@ -329,12 +332,15 @@ DM_TEST(dm_test_pci_addr_flat, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT |
 static int dm_test_pci_addr_live(struct unit_test_state *uts)
 {
        struct udevice *swap1f, *swap1;
+       fdt_size_t size;
 
        ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f));
-       ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f));
+       ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f, &size));
+       ut_asserteq(0, size);
 
        ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1));
-       ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1));
+       ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1, &size));
+       ut_asserteq(0, size);
 
        return 0;
 }