i2c: piix4: Add EFCH MMIO support to region request and release
authorTerry Bowman <terry.bowman@amd.com>
Wed, 9 Feb 2022 17:27:14 +0000 (11:27 -0600)
committerWolfram Sang <wsa@kernel.org>
Fri, 11 Feb 2022 14:38:03 +0000 (15:38 +0100)
EFCH cd6h/cd7h port I/O may no longer be available on later AMD
processors and it is recommended to use MMIO instead. Update the
request and release functions to support MMIO.

MMIO request/release and mmapping require details during cleanup.
Add a MMIO configuration structure containing resource and vaddress
details for mapping the region, accessing the region, and releasing
the region.

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: Jean Delvare <jdelvare@suse.de>
[wsa: rebased after fixup in previous patch]
Signed-off-by: Wolfram Sang <wsa@kernel.org>
drivers/i2c/busses/i2c-piix4.c

index efe51f6..d06998f 100644 (file)
@@ -98,6 +98,9 @@
 #define SB800_PIIX4_PORT_IDX_MASK_KERNCZ       0x18
 #define SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ      3
 
+#define SB800_PIIX4_FCH_PM_ADDR                        0xFED80300
+#define SB800_PIIX4_FCH_PM_SIZE                        8
+
 /* insmod parameters */
 
 /* If force is set to anything different from 0, we forcibly enable the
@@ -156,6 +159,12 @@ static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = {
 };
 static const char *piix4_aux_port_name_sb800 = " port 1";
 
+struct sb800_mmio_cfg {
+       void __iomem *addr;
+       struct resource *res;
+       bool use_mmio;
+};
+
 struct i2c_piix4_adapdata {
        unsigned short smba;
 
@@ -163,10 +172,40 @@ struct i2c_piix4_adapdata {
        bool sb800_main;
        bool notify_imc;
        u8 port;                /* Port number, shifted */
+       struct sb800_mmio_cfg mmio_cfg;
 };
 
-static int piix4_sb800_region_request(struct device *dev)
+static int piix4_sb800_region_request(struct device *dev,
+                                     struct sb800_mmio_cfg *mmio_cfg)
 {
+       if (mmio_cfg->use_mmio) {
+               struct resource *res;
+               void __iomem *addr;
+
+               res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
+                                              SB800_PIIX4_FCH_PM_SIZE,
+                                              "sb800_piix4_smb");
+               if (!res) {
+                       dev_err(dev,
+                               "SMBus base address memory region 0x%x already in use.\n",
+                               SB800_PIIX4_FCH_PM_ADDR);
+                       return -EBUSY;
+               }
+
+               addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
+                              SB800_PIIX4_FCH_PM_SIZE);
+               if (!addr) {
+                       release_resource(res);
+                       dev_err(dev, "SMBus base address mapping failed.\n");
+                       return -ENOMEM;
+               }
+
+               mmio_cfg->res = res;
+               mmio_cfg->addr = addr;
+
+               return 0;
+       }
+
        if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE,
                                  "sb800_piix4_smb")) {
                dev_err(dev,
@@ -178,8 +217,15 @@ static int piix4_sb800_region_request(struct device *dev)
        return 0;
 }
 
-static void piix4_sb800_region_release(struct device *dev)
+static void piix4_sb800_region_release(struct device *dev,
+                                      struct sb800_mmio_cfg *mmio_cfg)
 {
+       if (mmio_cfg->use_mmio) {
+               iounmap(mmio_cfg->addr);
+               release_resource(mmio_cfg->res);
+               return;
+       }
+
        release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE);
 }
 
@@ -288,11 +334,13 @@ static int piix4_setup_sb800_smba(struct pci_dev *PIIX4_dev,
                                  u8 *smb_en_status,
                                  unsigned short *piix4_smba)
 {
+       struct sb800_mmio_cfg mmio_cfg;
        u8 smba_en_lo;
        u8 smba_en_hi;
        int retval;
 
-       retval = piix4_sb800_region_request(&PIIX4_dev->dev);
+       mmio_cfg.use_mmio = 0;
+       retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
        if (retval)
                return retval;
 
@@ -301,7 +349,7 @@ static int piix4_setup_sb800_smba(struct pci_dev *PIIX4_dev,
        outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX);
        smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1);
 
-       piix4_sb800_region_release(&PIIX4_dev->dev);
+       piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg);
 
        if (!smb_en) {
                *smb_en_status = smba_en_lo & 0x10;
@@ -328,6 +376,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        unsigned short piix4_smba;
        u8 smb_en, smb_en_status, port_sel;
        u8 i2ccfg, i2ccfg_offset = 0x10;
+       struct sb800_mmio_cfg mmio_cfg;
        int retval;
 
        /* SB800 and later SMBus does not support forcing address */
@@ -407,7 +456,8 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
                        piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
                }
        } else {
-               retval = piix4_sb800_region_request(&PIIX4_dev->dev);
+               mmio_cfg.use_mmio = 0;
+               retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg);
                if (retval) {
                        release_region(piix4_smba, SMBIOSIZE);
                        return retval;
@@ -420,7 +470,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
                                       SB800_PIIX4_PORT_IDX;
                piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK;
                piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT;
-               piix4_sb800_region_release(&PIIX4_dev->dev);
+               piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg);
        }
 
        dev_info(&PIIX4_dev->dev,
@@ -731,7 +781,7 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
        u8 prev_port;
        int retval;
 
-       retval = piix4_sb800_region_request(&adap->dev);
+       retval = piix4_sb800_region_request(&adap->dev, &adapdata->mmio_cfg);
        if (retval)
                return retval;
 
@@ -802,7 +852,7 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr,
                piix4_imc_wakeup();
 
 release:
-       piix4_sb800_region_release(&adap->dev);
+       piix4_sb800_region_release(&adap->dev, &adapdata->mmio_cfg);
        return retval;
 }