From: Terry Bowman <terry.bowman@xxxxxxx> commit 7c148722d074c29fb998578eea5de3c14b9608c9 upstream. 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@xxxxxxx> Reviewed-by: Andy Shevchenko <andy.shevchenko@xxxxxxxxx> Reviewed-by: Jean Delvare <jdelvare@xxxxxxx> [wsa: rebased after fixup in previous patch] Signed-off-by: Wolfram Sang <wsa@xxxxxxxxxx> Cc: Mario Limonciello <Mario.Limonciello@xxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/i2c/busses/i2c-piix4.c | 66 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 8 deletions(-) --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -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 }; 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(st 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 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 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_ 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_ 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_ 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 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 piix4_imc_wakeup(); release: - piix4_sb800_region_release(&adap->dev); + piix4_sb800_region_release(&adap->dev, &adapdata->mmio_cfg); return retval; }