diff mbox

[U-Boot,20/69] x86: Move common LPC code to its own place

Message ID 1457317732-18406-21-git-send-email-sjg@chromium.org
State Superseded
Delegated to: Bin Meng
Headers show

Commit Message

Simon Glass March 7, 2016, 2:28 a.m. UTC
Some of the LPC code is common to several Intel LPC devices. Move it into a
common location.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/x86/cpu/intel_common/Makefile        |   1 +
 arch/x86/cpu/intel_common/lpc_common.c    | 102 ++++++++++++++++++++++++++++++
 arch/x86/cpu/ivybridge/bd82x6x.c          |  16 +----
 arch/x86/cpu/ivybridge/lpc.c              |  73 ++-------------------
 arch/x86/include/asm/arch-ivybridge/pch.h |   2 -
 arch/x86/include/asm/lpc_common.h         |  59 +++++++++++++++++
 6 files changed, 168 insertions(+), 85 deletions(-)
 create mode 100644 arch/x86/cpu/intel_common/lpc_common.c
 create mode 100644 arch/x86/include/asm/lpc_common.h

Comments

Bin Meng March 11, 2016, 5:05 a.m. UTC | #1
Hi Simon,

On Mon, Mar 7, 2016 at 10:28 AM, Simon Glass <sjg@chromium.org> wrote:
> Some of the LPC code is common to several Intel LPC devices. Move it into a
> common location.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  arch/x86/cpu/intel_common/Makefile        |   1 +
>  arch/x86/cpu/intel_common/lpc_common.c    | 102 ++++++++++++++++++++++++++++++
>  arch/x86/cpu/ivybridge/bd82x6x.c          |  16 +----
>  arch/x86/cpu/ivybridge/lpc.c              |  73 ++-------------------
>  arch/x86/include/asm/arch-ivybridge/pch.h |   2 -
>  arch/x86/include/asm/lpc_common.h         |  59 +++++++++++++++++
>  6 files changed, 168 insertions(+), 85 deletions(-)
>  create mode 100644 arch/x86/cpu/intel_common/lpc_common.c
>  create mode 100644 arch/x86/include/asm/lpc_common.h
>
> diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
> index bc7c3ff..36c150d 100644
> --- a/arch/x86/cpu/intel_common/Makefile
> +++ b/arch/x86/cpu/intel_common/Makefile
> @@ -5,6 +5,7 @@
>  #
>
>  obj-$(CONFIG_HAVE_MRC) += car.o
> +obj-y += lpc_common.o
>  ifndef CONFIG_TARGET_EFI
>  obj-y += microcode_intel.o
>  endif
> diff --git a/arch/x86/cpu/intel_common/lpc_common.c b/arch/x86/cpu/intel_common/lpc_common.c
> new file mode 100644
> index 0000000..2a3b941
> --- /dev/null
> +++ b/arch/x86/cpu/intel_common/lpc_common.c
> @@ -0,0 +1,102 @@
> +/*
> + * Copyright (c) 2016 Google, Inc
> + *
> + * SPDX-License-Identifier:    GPL-2.0
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <fdtdec.h>
> +#include <pch.h>
> +#include <pci.h>
> +#include <asm/intel_regs.h>
> +#include <asm/io.h>
> +#include <asm/lpc_common.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +/*
> + * Enable Prefetching and Caching.
> + */

nits: single-line comment format

> +static void enable_spi_prefetch(struct udevice *pch)
> +{
> +       u8 reg8;
> +
> +       dm_pci_read_config8(pch, 0xdc, &reg8);
> +       reg8 &= ~(3 << 2);
> +       reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
> +       dm_pci_write_config8(pch, 0xdc, reg8);
> +}
> +
> +static void enable_port80_on_lpc(struct udevice *pch)
> +{
> +       /* Enable port 80 POST on LPC */
> +       dm_pci_write_config32(pch, PCH_RCBA_BASE, RCB_BASE_ADDRESS | 1);
> +       clrbits_le32(RCB_REG(GCS), 4);
> +}
> +
> +/**
> + * lpc_early_init() - set up LPC serial ports and other early things
> + *
> + * @dev:       LPC device
> + * @return 0 if OK, -ve on error
> + */
> +int lpc_common_early_init(struct udevice *dev)
> +{
> +       struct udevice *pch = dev->parent;
> +       struct reg_info {
> +               u32 base;
> +               u32 size;
> +       } values[4], *ptr;
> +       int count;
> +       int i;
> +
> +       count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
> +                       "intel,gen-dec", (u32 *)values,
> +                       sizeof(values) / sizeof(u32));
> +       if (count < 0)
> +               return -EINVAL;
> +
> +       /* Set COM1/COM2 decode range */
> +       dm_pci_write_config16(pch, LPC_IO_DEC, 0x0010);
> +
> +       /* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */
> +       dm_pci_write_config16(pch, LPC_EN, KBC_LPC_EN | MC_LPC_EN |
> +                             GAMEL_LPC_EN | COMA_LPC_EN);
> +
> +       /* Write all registers but use 0 if we run out of data */
> +       count = count * sizeof(u32) / sizeof(values[0]);
> +       for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) {
> +               u32 reg = 0;
> +
> +               if (i < count)
> +                       reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16);
> +               dm_pci_write_config32(pch, LPC_GENX_DEC(i), reg);
> +       }
> +
> +       enable_spi_prefetch(pch);
> +
> +       /* This is already done in start.S, but let's do it in C */
> +       enable_port80_on_lpc(pch);
> +
> +       return 0;
> +}
> +
> +int lpc_set_spi_protect(struct udevice *dev, int bios_ctrl, bool protect)
> +{
> +       uint8_t bios_cntl;
> +
> +       /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
> +       dm_pci_read_config8(dev, bios_ctrl, &bios_cntl);
> +       if (protect) {
> +               bios_cntl &= ~BIOS_CTRL_BIOSWE;
> +               bios_cntl |= BIT(5);
> +       } else {
> +               bios_cntl |= BIOS_CTRL_BIOSWE;
> +               bios_cntl &= ~BIT(5);
> +       }
> +       dm_pci_write_config8(dev, bios_ctrl, bios_cntl);
> +
> +       return 0;
> +}
> diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c
> index 55057e0..4c039ac 100644
> --- a/arch/x86/cpu/ivybridge/bd82x6x.c
> +++ b/arch/x86/cpu/ivybridge/bd82x6x.c
> @@ -14,6 +14,7 @@
>  #include <asm/intel_regs.h>
>  #include <asm/io.h>
>  #include <asm/lapic.h>
> +#include <asm/lpc_common.h>
>  #include <asm/pci.h>
>  #include <asm/arch/bd82x6x.h>
>  #include <asm/arch/model_206ax.h>
> @@ -188,20 +189,7 @@ static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
>
>  static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
>  {
> -       uint8_t bios_cntl;
> -
> -       /* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
> -       dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl);
> -       if (protect) {
> -               bios_cntl &= ~BIOS_CTRL_BIOSWE;
> -               bios_cntl |= BIT(5);
> -       } else {
> -               bios_cntl |= BIOS_CTRL_BIOSWE;
> -               bios_cntl &= ~BIT(5);
> -       }
> -       dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl);
> -
> -       return 0;
> +       return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
>  }
>
>  static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep)
> diff --git a/arch/x86/cpu/ivybridge/lpc.c b/arch/x86/cpu/ivybridge/lpc.c
> index 26ffaa0..88ab797 100644
> --- a/arch/x86/cpu/ivybridge/lpc.c
> +++ b/arch/x86/cpu/ivybridge/lpc.c
> @@ -17,6 +17,7 @@
>  #include <asm/interrupt.h>
>  #include <asm/io.h>
>  #include <asm/ioapic.h>
> +#include <asm/lpc_common.h>
>  #include <asm/pci.h>
>  #include <asm/arch/pch.h>
>
> @@ -405,26 +406,6 @@ static void pch_fixups(struct udevice *pch)
>         setbits_le32(RCB_REG(0x21a8), 0x3);
>  }
>
> -/*
> - * Enable Prefetching and Caching.
> - */
> -static void enable_spi_prefetch(struct udevice *pch)
> -{
> -       u8 reg8;
> -
> -       dm_pci_read_config8(pch, 0xdc, &reg8);
> -       reg8 &= ~(3 << 2);
> -       reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
> -       dm_pci_write_config8(pch, 0xdc, reg8);
> -}
> -
> -static void enable_port80_on_lpc(struct udevice *pch)
> -{
> -       /* Enable port 80 POST on LPC */
> -       dm_pci_write_config32(pch, PCH_RCBA_BASE, RCB_BASE_ADDRESS | 1);
> -       clrbits_le32(RCB_REG(GCS), 4);
> -}
> -
>  static void set_spi_speed(void)
>  {
>         u32 fdod;
> @@ -441,54 +422,6 @@ static void set_spi_speed(void)
>         clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
>  }
>
> -/**
> - * lpc_early_init() - set up LPC serial ports and other early things
> - *
> - * @dev:       LPC device
> - * @return 0 if OK, -ve on error
> - */
> -static int lpc_early_init(struct udevice *dev)
> -{
> -       struct reg_info {
> -               u32 base;
> -               u32 size;
> -       } values[4], *ptr;
> -       int count;
> -       int i;
> -
> -       count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
> -                       "intel,gen-dec", (u32 *)values,
> -                       sizeof(values) / sizeof(u32));
> -       if (count < 0)
> -               return -EINVAL;
> -
> -       /* Set COM1/COM2 decode range */
> -       dm_pci_write_config16(dev->parent, LPC_IO_DEC, 0x0010);
> -
> -       /* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */
> -       dm_pci_write_config16(dev->parent, LPC_EN, KBC_LPC_EN | MC_LPC_EN |
> -                             GAMEL_LPC_EN | COMA_LPC_EN);
> -
> -       /* Write all registers but use 0 if we run out of data */
> -       count = count * sizeof(u32) / sizeof(values[0]);
> -       for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) {
> -               u32 reg = 0;
> -
> -               if (i < count)
> -                       reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16);
> -               dm_pci_write_config32(dev->parent, LPC_GENX_DEC(i), reg);
> -       }
> -
> -       enable_spi_prefetch(dev->parent);
> -
> -       /* This is already done in start.S, but let's do it in C */
> -       enable_port80_on_lpc(dev->parent);
> -
> -       set_spi_speed();
> -
> -       return 0;
> -}
> -
>  static int lpc_init_extra(struct udevice *dev)
>  {
>         struct udevice *pch = dev->parent;
> @@ -551,6 +484,8 @@ static int lpc_init_extra(struct udevice *dev)
>
>  static int bd82x6x_lpc_early_init(struct udevice *dev)
>  {
> +       set_spi_speed();
> +
>         /* Setting up Southbridge. In the northbridge code. */
>         debug("Setting up static southbridge registers\n");
>         dm_pci_write_config32(dev->parent, PCH_RCBA_BASE,
> @@ -575,7 +510,7 @@ static int bd82x6x_lpc_probe(struct udevice *dev)
>         int ret;
>
>         if (!(gd->flags & GD_FLG_RELOC)) {
> -               ret = lpc_early_init(dev);
> +               ret = lpc_common_early_init(dev);
>                 if (ret) {
>                         debug("%s: lpc_early_init() failed\n", __func__);
>                         return ret;
> diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h
> index 628b517..f96dc2b 100644
> --- a/arch/x86/include/asm/arch-ivybridge/pch.h
> +++ b/arch/x86/include/asm/arch-ivybridge/pch.h
> @@ -211,8 +211,6 @@
>
>  #define SMBUS_TIMEOUT          (10 * 1000 * 100)
>
> -#define PCH_RCBA_BASE          0xf0
> -
>  #define VCH            0x0000  /* 32bit */
>  #define VCAP1          0x0004  /* 32bit */
>  #define VCAP2          0x0008  /* 32bit */
> diff --git a/arch/x86/include/asm/lpc_common.h b/arch/x86/include/asm/lpc_common.h
> new file mode 100644
> index 0000000..bcfccaf
> --- /dev/null
> +++ b/arch/x86/include/asm/lpc_common.h
> @@ -0,0 +1,59 @@
> +/*
> + * Copyright (c) 2016 Google, Inc
> + *
> + * SPDX-License-Identifier:    GPL-2.0

nits: GPL-2.0+?

> + */
> +
> +#ifndef __asm_lpc_common_h
> +#define __asm_lpc_common_h

nits: all capital letters

> +
> +#define PCH_RCBA_BASE          0xf0
> +
> +#define RC             0x3400  /* 32bit */
> +#define GCS            0x3410  /* 32bit */
> +
> +#define PMBASE                 0x40
> +#define ACPI_CNTL              0x44
> +
> +#define LPC_IO_DEC             0x80 /* IO Decode Ranges Register */
> +#define  COMB_DEC_RANGE                (1 << 4)  /* 0x2f8-0x2ff (COM2) */
> +#define  COMA_DEC_RANGE                (0 << 0)  /* 0x3f8-0x3ff (COM1) */
> +#define LPC_EN                 0x82 /* LPC IF Enables Register */
> +#define  CNF2_LPC_EN           (1 << 13) /* 0x4e/0x4f */
> +#define  CNF1_LPC_EN           (1 << 12) /* 0x2e/0x2f */
> +#define  MC_LPC_EN             (1 << 11) /* 0x62/0x66 */
> +#define  KBC_LPC_EN            (1 << 10) /* 0x60/0x64 */
> +#define  GAMEH_LPC_EN          (1 << 9)  /* 0x208/0x20f */
> +#define  GAMEL_LPC_EN          (1 << 8)  /* 0x200/0x207 */
> +#define  FDD_LPC_EN            (1 << 3)  /* LPC_IO_DEC[12] */
> +#define  LPT_LPC_EN            (1 << 2)  /* LPC_IO_DEC[9:8] */
> +#define  COMB_LPC_EN           (1 << 1)  /* LPC_IO_DEC[6:4] */
> +#define  COMA_LPC_EN           (1 << 0)  /* LPC_IO_DEC[3:2] */
> +#define LPC_GEN1_DEC           0x84 /* LPC IF Generic Decode Range 1 */
> +#define LPC_GEN2_DEC           0x88 /* LPC IF Generic Decode Range 2 */
> +#define LPC_GEN3_DEC           0x8c /* LPC IF Generic Decode Range 3 */
> +#define LPC_GEN4_DEC           0x90 /* LPC IF Generic Decode Range 4 */
> +#define LPC_GENX_DEC(x)                (0x84 + 4 * (x))
> +#define  GEN_DEC_RANGE_256B    0xfc0000  /* 256 Bytes */
> +#define  GEN_DEC_RANGE_128B    0x7c0000  /* 128 Bytes */
> +#define  GEN_DEC_RANGE_64B     0x3c0000  /* 64 Bytes */
> +#define  GEN_DEC_RANGE_32B     0x1c0000  /* 32 Bytes */
> +#define  GEN_DEC_RANGE_16B     0x0c0000  /* 16 Bytes */
> +#define  GEN_DEC_RANGE_8B      0x040000  /* 8 Bytes */
> +#define  GEN_DEC_RANGE_4B      0x000000  /* 4 Bytes */
> +#define  GEN_DEC_RANGE_EN      (1 << 0)  /* Range Enable */
> +
> +/**
> + * lpc_common_early_init() - Set up common LPC init
> + *
> + * This sets up the legacy decode areas, GEN_DEC, SPI prefetch and Port80. It
> + * also puts the RCB in the correct place so that RCB_REG() works.
> + *
> + * @dev:       LPC device (a child of the PCH)
> + * @return 0 on success, -ve on error
> + */
> +int lpc_common_early_init(struct udevice *dev);
> +
> +int lpc_set_spi_protect(struct udevice *dev, int bios_ctrl, bool protect);
> +
> +#endif
> --

Reviewed-by: Bin Meng <bmeng.cn@gmail.com>

Regards,
Bin
Bin Meng March 11, 2016, 5:18 a.m. UTC | #2
On Fri, Mar 11, 2016 at 1:05 PM, Bin Meng <bmeng.cn@gmail.com> wrote:
> Hi Simon,
>
> On Mon, Mar 7, 2016 at 10:28 AM, Simon Glass <sjg@chromium.org> wrote:
>> Some of the LPC code is common to several Intel LPC devices. Move it into a
>> common location.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>>
>>  arch/x86/cpu/intel_common/Makefile        |   1 +
>>  arch/x86/cpu/intel_common/lpc_common.c    | 102 ++++++++++++++++++++++++++++++

Forget to mention: can we just use "lpc.c" as the name as "_common" is
already in the directory name?

>>  arch/x86/cpu/ivybridge/bd82x6x.c          |  16 +----
>>  arch/x86/cpu/ivybridge/lpc.c              |  73 ++-------------------
>>  arch/x86/include/asm/arch-ivybridge/pch.h |   2 -
>>  arch/x86/include/asm/lpc_common.h         |  59 +++++++++++++++++
>>  6 files changed, 168 insertions(+), 85 deletions(-)
>>  create mode 100644 arch/x86/cpu/intel_common/lpc_common.c
>>  create mode 100644 arch/x86/include/asm/lpc_common.h
>>

Regards,
Bin
diff mbox

Patch

diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile
index bc7c3ff..36c150d 100644
--- a/arch/x86/cpu/intel_common/Makefile
+++ b/arch/x86/cpu/intel_common/Makefile
@@ -5,6 +5,7 @@ 
 #
 
 obj-$(CONFIG_HAVE_MRC) += car.o
+obj-y += lpc_common.o
 ifndef CONFIG_TARGET_EFI
 obj-y += microcode_intel.o
 endif
diff --git a/arch/x86/cpu/intel_common/lpc_common.c b/arch/x86/cpu/intel_common/lpc_common.c
new file mode 100644
index 0000000..2a3b941
--- /dev/null
+++ b/arch/x86/cpu/intel_common/lpc_common.c
@@ -0,0 +1,102 @@ 
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <pch.h>
+#include <pci.h>
+#include <asm/intel_regs.h>
+#include <asm/io.h>
+#include <asm/lpc_common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Enable Prefetching and Caching.
+ */
+static void enable_spi_prefetch(struct udevice *pch)
+{
+	u8 reg8;
+
+	dm_pci_read_config8(pch, 0xdc, &reg8);
+	reg8 &= ~(3 << 2);
+	reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
+	dm_pci_write_config8(pch, 0xdc, reg8);
+}
+
+static void enable_port80_on_lpc(struct udevice *pch)
+{
+	/* Enable port 80 POST on LPC */
+	dm_pci_write_config32(pch, PCH_RCBA_BASE, RCB_BASE_ADDRESS | 1);
+	clrbits_le32(RCB_REG(GCS), 4);
+}
+
+/**
+ * lpc_early_init() - set up LPC serial ports and other early things
+ *
+ * @dev:	LPC device
+ * @return 0 if OK, -ve on error
+ */
+int lpc_common_early_init(struct udevice *dev)
+{
+	struct udevice *pch = dev->parent;
+	struct reg_info {
+		u32 base;
+		u32 size;
+	} values[4], *ptr;
+	int count;
+	int i;
+
+	count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
+			"intel,gen-dec", (u32 *)values,
+			sizeof(values) / sizeof(u32));
+	if (count < 0)
+		return -EINVAL;
+
+	/* Set COM1/COM2 decode range */
+	dm_pci_write_config16(pch, LPC_IO_DEC, 0x0010);
+
+	/* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */
+	dm_pci_write_config16(pch, LPC_EN, KBC_LPC_EN | MC_LPC_EN |
+			      GAMEL_LPC_EN | COMA_LPC_EN);
+
+	/* Write all registers but use 0 if we run out of data */
+	count = count * sizeof(u32) / sizeof(values[0]);
+	for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) {
+		u32 reg = 0;
+
+		if (i < count)
+			reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16);
+		dm_pci_write_config32(pch, LPC_GENX_DEC(i), reg);
+	}
+
+	enable_spi_prefetch(pch);
+
+	/* This is already done in start.S, but let's do it in C */
+	enable_port80_on_lpc(pch);
+
+	return 0;
+}
+
+int lpc_set_spi_protect(struct udevice *dev, int bios_ctrl, bool protect)
+{
+	uint8_t bios_cntl;
+
+	/* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
+	dm_pci_read_config8(dev, bios_ctrl, &bios_cntl);
+	if (protect) {
+		bios_cntl &= ~BIOS_CTRL_BIOSWE;
+		bios_cntl |= BIT(5);
+	} else {
+		bios_cntl |= BIOS_CTRL_BIOSWE;
+		bios_cntl &= ~BIT(5);
+	}
+	dm_pci_write_config8(dev, bios_ctrl, bios_cntl);
+
+	return 0;
+}
diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c
index 55057e0..4c039ac 100644
--- a/arch/x86/cpu/ivybridge/bd82x6x.c
+++ b/arch/x86/cpu/ivybridge/bd82x6x.c
@@ -14,6 +14,7 @@ 
 #include <asm/intel_regs.h>
 #include <asm/io.h>
 #include <asm/lapic.h>
+#include <asm/lpc_common.h>
 #include <asm/pci.h>
 #include <asm/arch/bd82x6x.h>
 #include <asm/arch/model_206ax.h>
@@ -188,20 +189,7 @@  static int bd82x6x_pch_get_spi_base(struct udevice *dev, ulong *sbasep)
 
 static int bd82x6x_set_spi_protect(struct udevice *dev, bool protect)
 {
-	uint8_t bios_cntl;
-
-	/* Adjust the BIOS write protect and SMM BIOS Write Protect Disable */
-	dm_pci_read_config8(dev, BIOS_CTRL, &bios_cntl);
-	if (protect) {
-		bios_cntl &= ~BIOS_CTRL_BIOSWE;
-		bios_cntl |= BIT(5);
-	} else {
-		bios_cntl |= BIOS_CTRL_BIOSWE;
-		bios_cntl &= ~BIT(5);
-	}
-	dm_pci_write_config8(dev, BIOS_CTRL, bios_cntl);
-
-	return 0;
+	return lpc_set_spi_protect(dev, BIOS_CTRL, protect);
 }
 
 static int bd82x6x_get_gpio_base(struct udevice *dev, u32 *gbasep)
diff --git a/arch/x86/cpu/ivybridge/lpc.c b/arch/x86/cpu/ivybridge/lpc.c
index 26ffaa0..88ab797 100644
--- a/arch/x86/cpu/ivybridge/lpc.c
+++ b/arch/x86/cpu/ivybridge/lpc.c
@@ -17,6 +17,7 @@ 
 #include <asm/interrupt.h>
 #include <asm/io.h>
 #include <asm/ioapic.h>
+#include <asm/lpc_common.h>
 #include <asm/pci.h>
 #include <asm/arch/pch.h>
 
@@ -405,26 +406,6 @@  static void pch_fixups(struct udevice *pch)
 	setbits_le32(RCB_REG(0x21a8), 0x3);
 }
 
-/*
- * Enable Prefetching and Caching.
- */
-static void enable_spi_prefetch(struct udevice *pch)
-{
-	u8 reg8;
-
-	dm_pci_read_config8(pch, 0xdc, &reg8);
-	reg8 &= ~(3 << 2);
-	reg8 |= (2 << 2); /* Prefetching and Caching Enabled */
-	dm_pci_write_config8(pch, 0xdc, reg8);
-}
-
-static void enable_port80_on_lpc(struct udevice *pch)
-{
-	/* Enable port 80 POST on LPC */
-	dm_pci_write_config32(pch, PCH_RCBA_BASE, RCB_BASE_ADDRESS | 1);
-	clrbits_le32(RCB_REG(GCS), 4);
-}
-
 static void set_spi_speed(void)
 {
 	u32 fdod;
@@ -441,54 +422,6 @@  static void set_spi_speed(void)
 	clrsetbits_8(RCB_REG(SPI_FREQ_SWSEQ), 7, fdod);
 }
 
-/**
- * lpc_early_init() - set up LPC serial ports and other early things
- *
- * @dev:	LPC device
- * @return 0 if OK, -ve on error
- */
-static int lpc_early_init(struct udevice *dev)
-{
-	struct reg_info {
-		u32 base;
-		u32 size;
-	} values[4], *ptr;
-	int count;
-	int i;
-
-	count = fdtdec_get_int_array_count(gd->fdt_blob, dev->of_offset,
-			"intel,gen-dec", (u32 *)values,
-			sizeof(values) / sizeof(u32));
-	if (count < 0)
-		return -EINVAL;
-
-	/* Set COM1/COM2 decode range */
-	dm_pci_write_config16(dev->parent, LPC_IO_DEC, 0x0010);
-
-	/* Enable PS/2 Keyboard/Mouse, EC areas and COM1 */
-	dm_pci_write_config16(dev->parent, LPC_EN, KBC_LPC_EN | MC_LPC_EN |
-			      GAMEL_LPC_EN | COMA_LPC_EN);
-
-	/* Write all registers but use 0 if we run out of data */
-	count = count * sizeof(u32) / sizeof(values[0]);
-	for (i = 0, ptr = values; i < ARRAY_SIZE(values); i++, ptr++) {
-		u32 reg = 0;
-
-		if (i < count)
-			reg = ptr->base | PCI_COMMAND_IO | (ptr->size << 16);
-		dm_pci_write_config32(dev->parent, LPC_GENX_DEC(i), reg);
-	}
-
-	enable_spi_prefetch(dev->parent);
-
-	/* This is already done in start.S, but let's do it in C */
-	enable_port80_on_lpc(dev->parent);
-
-	set_spi_speed();
-
-	return 0;
-}
-
 static int lpc_init_extra(struct udevice *dev)
 {
 	struct udevice *pch = dev->parent;
@@ -551,6 +484,8 @@  static int lpc_init_extra(struct udevice *dev)
 
 static int bd82x6x_lpc_early_init(struct udevice *dev)
 {
+	set_spi_speed();
+
 	/* Setting up Southbridge. In the northbridge code. */
 	debug("Setting up static southbridge registers\n");
 	dm_pci_write_config32(dev->parent, PCH_RCBA_BASE,
@@ -575,7 +510,7 @@  static int bd82x6x_lpc_probe(struct udevice *dev)
 	int ret;
 
 	if (!(gd->flags & GD_FLG_RELOC)) {
-		ret = lpc_early_init(dev);
+		ret = lpc_common_early_init(dev);
 		if (ret) {
 			debug("%s: lpc_early_init() failed\n", __func__);
 			return ret;
diff --git a/arch/x86/include/asm/arch-ivybridge/pch.h b/arch/x86/include/asm/arch-ivybridge/pch.h
index 628b517..f96dc2b 100644
--- a/arch/x86/include/asm/arch-ivybridge/pch.h
+++ b/arch/x86/include/asm/arch-ivybridge/pch.h
@@ -211,8 +211,6 @@ 
 
 #define SMBUS_TIMEOUT		(10 * 1000 * 100)
 
-#define PCH_RCBA_BASE		0xf0
-
 #define VCH		0x0000	/* 32bit */
 #define VCAP1		0x0004	/* 32bit */
 #define VCAP2		0x0008	/* 32bit */
diff --git a/arch/x86/include/asm/lpc_common.h b/arch/x86/include/asm/lpc_common.h
new file mode 100644
index 0000000..bcfccaf
--- /dev/null
+++ b/arch/x86/include/asm/lpc_common.h
@@ -0,0 +1,59 @@ 
+/*
+ * Copyright (c) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0
+ */
+
+#ifndef __asm_lpc_common_h
+#define __asm_lpc_common_h
+
+#define PCH_RCBA_BASE		0xf0
+
+#define RC		0x3400	/* 32bit */
+#define GCS		0x3410	/* 32bit */
+
+#define PMBASE			0x40
+#define ACPI_CNTL		0x44
+
+#define LPC_IO_DEC		0x80 /* IO Decode Ranges Register */
+#define  COMB_DEC_RANGE		(1 << 4)  /* 0x2f8-0x2ff (COM2) */
+#define  COMA_DEC_RANGE		(0 << 0)  /* 0x3f8-0x3ff (COM1) */
+#define LPC_EN			0x82 /* LPC IF Enables Register */
+#define  CNF2_LPC_EN		(1 << 13) /* 0x4e/0x4f */
+#define  CNF1_LPC_EN		(1 << 12) /* 0x2e/0x2f */
+#define  MC_LPC_EN		(1 << 11) /* 0x62/0x66 */
+#define  KBC_LPC_EN		(1 << 10) /* 0x60/0x64 */
+#define  GAMEH_LPC_EN		(1 << 9)  /* 0x208/0x20f */
+#define  GAMEL_LPC_EN		(1 << 8)  /* 0x200/0x207 */
+#define  FDD_LPC_EN		(1 << 3)  /* LPC_IO_DEC[12] */
+#define  LPT_LPC_EN		(1 << 2)  /* LPC_IO_DEC[9:8] */
+#define  COMB_LPC_EN		(1 << 1)  /* LPC_IO_DEC[6:4] */
+#define  COMA_LPC_EN		(1 << 0)  /* LPC_IO_DEC[3:2] */
+#define LPC_GEN1_DEC		0x84 /* LPC IF Generic Decode Range 1 */
+#define LPC_GEN2_DEC		0x88 /* LPC IF Generic Decode Range 2 */
+#define LPC_GEN3_DEC		0x8c /* LPC IF Generic Decode Range 3 */
+#define LPC_GEN4_DEC		0x90 /* LPC IF Generic Decode Range 4 */
+#define LPC_GENX_DEC(x)		(0x84 + 4 * (x))
+#define  GEN_DEC_RANGE_256B	0xfc0000  /* 256 Bytes */
+#define  GEN_DEC_RANGE_128B	0x7c0000  /* 128 Bytes */
+#define  GEN_DEC_RANGE_64B	0x3c0000  /* 64 Bytes */
+#define  GEN_DEC_RANGE_32B	0x1c0000  /* 32 Bytes */
+#define  GEN_DEC_RANGE_16B	0x0c0000  /* 16 Bytes */
+#define  GEN_DEC_RANGE_8B	0x040000  /* 8 Bytes */
+#define  GEN_DEC_RANGE_4B	0x000000  /* 4 Bytes */
+#define  GEN_DEC_RANGE_EN	(1 << 0)  /* Range Enable */
+
+/**
+ * lpc_common_early_init() - Set up common LPC init
+ *
+ * This sets up the legacy decode areas, GEN_DEC, SPI prefetch and Port80. It
+ * also puts the RCB in the correct place so that RCB_REG() works.
+ *
+ * @dev:	LPC device (a child of the PCH)
+ * @return 0 on success, -ve on error
+ */
+int lpc_common_early_init(struct udevice *dev);
+
+int lpc_set_spi_protect(struct udevice *dev, int bios_ctrl, bool protect);
+
+#endif