Commit 7c148722 authored by Terry Bowman's avatar Terry Bowman Committed by Wolfram Sang
Browse files

i2c: piix4: Add EFCH MMIO support to region request and release



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: default avatarTerry Bowman <terry.bowman@amd.com>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Reviewed-by: default avatarJean Delvare <jdelvare@suse.de>
[wsa: rebased after fixup in previous patch]
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
parent fbafbd51
Loading
Loading
Loading
Loading
+58 −8
Original line number Diff line number Diff line
@@ -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;
}