summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch905
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch26
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch417
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch2
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch50
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch101
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch88
8 files changed, 1191 insertions, 442 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch
index 08be45ff7..146a725dd 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0008-Add-ASPEED-SGPIO-driver.patch
@@ -1,18 +1,17 @@
-From 323066b26f02f043e694463a8e0cd4ada465984b Mon Sep 17 00:00:00 2001
+From e6923abbc90b5b00bc9ea401fbb2a28971d19cbe Mon Sep 17 00:00:00 2001
From: "Feist, James" <james.feist@intel.com>
-Date: Mon, 5 Jun 2017 11:13:52 -0700
-Subject: [PATCH] Add ASPEED SGPIO driver.
+Date: Tue, 4 Jun 2019 14:00:39 -0700
+Subject: [PATCH] gpio: aspeed: add ASPEED SGPIO driver
-Port aspeed sgpio driver to OBMC Kernel and
-enable it on Purley config. Based off AST sdk 4.0.
+Add SGPIO driver support for Aspeed SoCs.
Signed-off-by: James Feist <james.feist@linux.intel.com>
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
drivers/gpio/Kconfig | 8 +
drivers/gpio/Makefile | 1 +
- drivers/gpio/sgpio-aspeed.c | 416 ++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 425 insertions(+)
+ drivers/gpio/sgpio-aspeed.c | 708 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 717 insertions(+)
create mode 100644 drivers/gpio/sgpio-aspeed.c
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
@@ -48,425 +47,717 @@ index 6700eee860b7..77c6ec0ee98f 100644
obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o
diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
new file mode 100644
-index 000000000000..9c4add74602a
+index 000000000000..6fb402a3f74d
--- /dev/null
+++ b/drivers/gpio/sgpio-aspeed.c
-@@ -0,0 +1,416 @@
-+// SPDX-License-Identifier: GPL-2.0
-+// Copyright (C) 2012-2017 ASPEED Technology Inc.
-+// Copyright (c) 2018 Intel Corporation
+@@ -0,0 +1,708 @@
++// SPDX-License-Identifier: GPL-2.0+
++// Copyright (c) 2019 Intel Corporation
+
-+#include <asm/mach/irq.h>
+#include <linux/bitfield.h>
++#include <linux/clk.h>
+#include <linux/gpio/driver.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
+#include <linux/module.h>
-+#include <linux/of_gpio.h>
++#include <linux/of.h>
+#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++
++#define ASPEED_SGPIO_CTRL 0x54
++#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
++#define ASPEED_SGPIO_CLK_DIV_MIN 1
++#define ASPEED_SGPIO_CLK_DIV_MAX 65535
++#define ASPEED_SGPIO_PINBYTES_MASK GENMASK(9, 6)
++#define ASPEED_SGPIO_PINBYTES_MIN 1
++#define ASPEED_SGPIO_PINBYTES_MAX 10
++#define ASPEED_SGPIO_ENABLE BIT(0)
++
++#define ASPEED_SGPIO_BUS_FREQ_DEFAULT 1000000
++
++struct aspeed_bank_props {
++ unsigned int bank;
++ u32 input;
++ u32 output;
++};
+
-+#ifdef ARCH_NR_GPIOS
-+#undef ARCH_NR_GPIOS
-+#endif
++struct aspeed_sgpio_config {
++ unsigned int nr_pgpios;
++ unsigned int nr_gpios;
++ const struct aspeed_bank_props *props;
++};
+
-+// TODO: move this to aspeed_sgpio_of_table
-+#if defined(CONFIG_MACH_ASPEED_G5)
-+#define GPIO_PORT_NUM 29
-+#elif defined(CONFIG_MACH_ASPEED_G4)
-+#define GPIO_PORT_NUM 28
-+#endif
++struct aspeed_sgpio {
++ struct gpio_chip chip;
++ spinlock_t lock;
++ void __iomem *base;
++ int irq;
++ const struct aspeed_sgpio_config *config;
+
-+// TODO: fix defines
-+#define GPIOS_PER_PORT 8
-+#define ARCH_NR_GPIOS (GPIOS_PER_PORT * GPIO_PORT_NUM)
-+#define ASPEED_SGPIO_CTRL 0x54
-+#define SGPIO_CHAIN_CHIP_BASE ARCH_NR_GPIOS
-+#define SGPIO_GROUP_NUMS 10
++ u32 *dcache;
++};
+
-+#define ASPEED_VIC_NUMS 64
-+#define ASPEED_FIQ_NUMS 64
-+#define ARCH_NR_I2C 14
++struct aspeed_sgpio_bank {
++ uint16_t val_reg;
++ uint16_t rdata_reg;
++ uint16_t tolerance_reg;
++ uint16_t irq_regs;
++ bool support_irq;
++ const char names[4][3];
++};
+
-+#define IRQ_I2C_CHAIN_START (ASPEED_VIC_NUMS + ASPEED_FIQ_NUMS)
-+#define IRQ_GPIO_CHAIN_START (IRQ_I2C_CHAIN_START + ARCH_NR_I2C)
-+#define IRQ_SGPIO_CHAIN_START (IRQ_GPIO_CHAIN_START + ARCH_NR_GPIOS)
++/*
++ * Note: The "val" register returns the input value sampled on the line.
++ * Or, it can be used for writing a value on the line.
++ *
++ * The "rdata" register returns the content of the write latch and thus
++ * can be used to read back what was last written reliably.
++ */
+
-+#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6)
-+#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16)
-+#define ASPEED_SGPIO_ENABLE BIT(0)
++static const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
++ {
++ .val_reg = 0x0000,
++ .rdata_reg = 0x0070,
++ .tolerance_reg = 0x0018,
++ .irq_regs = 0x0004,
++ .support_irq = false,
++ .names = { "OA", "OB", "OC", "OD" },
++ },
++ {
++ .val_reg = 0x001C,
++ .rdata_reg = 0x0074,
++ .tolerance_reg = 0x0034,
++ .irq_regs = 0x0020,
++ .support_irq = false,
++ .names = { "OE", "OF", "OG", "OH" },
++ },
++ {
++ .val_reg = 0x0038,
++ .rdata_reg = 0x0078,
++ .tolerance_reg = 0x0050,
++ .irq_regs = 0x003C,
++ .support_irq = false,
++ .names = { "OI", "OJ" },
++ },
++ {
++ .val_reg = 0x0000,
++ .rdata_reg = 0x0070,
++ .tolerance_reg = 0x0018,
++ .irq_regs = 0x0004,
++ .support_irq = true,
++ .names = { "IA", "IB", "IC", "ID" },
++ },
++ {
++ .val_reg = 0x001C,
++ .rdata_reg = 0x0074,
++ .tolerance_reg = 0x0034,
++ .irq_regs = 0x0020,
++ .support_irq = true,
++ .names = { "IE", "IF", "IG", "IH" },
++ },
++ {
++ .val_reg = 0x0038,
++ .rdata_reg = 0x0078,
++ .tolerance_reg = 0x0050,
++ .irq_regs = 0x003C,
++ .support_irq = true,
++ .names = { "II", "IJ" },
++ },
++};
+
-+struct aspeed_sgpio {
-+ struct device *dev;
-+ int mirq; /* master irq */
-+ void __iomem *base;
-+// TODO: make below members as a struct member
-+ uint index;
-+ uint data_offset;
-+ uint data_read_offset;
-+ uint int_en_offset;
-+ uint int_type_offset;
-+ uint int_sts_offset;
-+ uint rst_tol_offset;
-+ struct gpio_chip chip;
++enum aspeed_sgpio_reg {
++ reg_val,
++ reg_rdata,
++ reg_irq_enable,
++ reg_irq_type0,
++ reg_irq_type1,
++ reg_irq_type2,
++ reg_irq_status,
++ reg_tolerance,
+};
+
-+uint aspeed_sgpio_to_irq(uint gpio)
++#define GPIO_IRQ_ENABLE 0x00
++#define GPIO_IRQ_TYPE0 0x04
++#define GPIO_IRQ_TYPE1 0x08
++#define GPIO_IRQ_TYPE2 0x0c
++#define GPIO_IRQ_STATUS 0x10
++
++/* This will be resolved at compile time */
++static inline void __iomem *bank_reg(struct aspeed_sgpio *gpio,
++ const struct aspeed_sgpio_bank *bank,
++ const enum aspeed_sgpio_reg reg)
+{
-+ return (gpio + IRQ_SGPIO_CHAIN_START);
++ switch (reg) {
++ case reg_val:
++ return gpio->base + bank->val_reg;
++ case reg_rdata:
++ return gpio->base + bank->rdata_reg;
++ case reg_irq_enable:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
++ case reg_irq_type0:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
++ case reg_irq_type1:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
++ case reg_irq_type2:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
++ case reg_irq_status:
++ return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
++ case reg_tolerance:
++ return gpio->base + bank->tolerance_reg;
++ default:
++ WARN_ON(1);
++ }
++
++ return NULL;
+}
-+EXPORT_SYMBOL(aspeed_sgpio_to_irq);
+
-+uint aspeed_irq_to_sgpio(uint irq)
++#define GPIO_BANK(x) ((x) >> 5)
++#define GPIO_OFFSET(x) ((x) & 0x1f)
++#define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
++
++static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
+{
-+ return (irq - IRQ_SGPIO_CHAIN_START);
++ unsigned int bank = GPIO_BANK(offset);
++
++ WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
++ return &aspeed_sgpio_banks[bank];
+}
-+EXPORT_SYMBOL(aspeed_irq_to_sgpio);
+
-+static int aspeed_sgpio_get(struct gpio_chip *chip, unsigned offset)
++static inline bool is_bank_props_sentinel(const struct aspeed_bank_props *props)
+{
-+ struct aspeed_sgpio *priv = gpiochip_get_data(chip);
-+ uint bit_nr = priv->index * GPIOS_PER_PORT + offset;
-+ unsigned long flags;
-+ u32 v;
++ return !(props->input || props->output);
++}
+
-+ local_irq_save(flags);
++static inline const struct aspeed_bank_props *find_bank_props(
++ struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = gpio->config->props;
+
-+ v = readl(priv->base + priv->data_offset);
-+ v &= BIT(bit_nr);
++ while (!is_bank_props_sentinel(props)) {
++ if (props->bank == GPIO_BANK(offset))
++ return props;
++ props++;
++ }
+
-+ if (v)
-+ v = 1;
-+ else
-+ v = 0;
++ return NULL;
++}
+
-+ local_irq_restore(flags);
++static inline bool have_input(struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
+
-+ dev_dbg(priv->dev, "%s, %s[%d]: %d\n", __func__, chip->label,
-+ offset, v);
++ return !props || (props->input & GPIO_BIT(offset));
++}
+
-+ return v;
++static inline bool have_output(struct aspeed_sgpio *gpio, unsigned int offset)
++{
++ const struct aspeed_bank_props *props = find_bank_props(gpio, offset);
++
++ return !props || (props->output & GPIO_BIT(offset));
+}
+
-+static void aspeed_sgpio_set(struct gpio_chip *chip, unsigned offset, int val)
++static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
+{
-+ struct aspeed_sgpio *priv = gpiochip_get_data(chip);
-+ uint bit_nr = priv->index * GPIOS_PER_PORT + offset;
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
++ const struct aspeed_sgpio_bank *bank = to_bank(offset);
++ enum aspeed_sgpio_reg reg;
++
++ if (have_output(gpio, offset))
++ reg = reg_rdata;
++ else
++ reg = reg_val;
++
++ return !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
++}
++
++static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
++{
++ const struct aspeed_sgpio_bank *bank = to_bank(offset);
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+ unsigned long flags;
-+ u32 v;
++ u32 reg;
+
-+ local_irq_save(flags);
++ if (!have_output(gpio, offset))
++ return;
+
-+ v = readl(priv->base + priv->data_read_offset);
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ reg = ioread32(bank_reg(gpio, bank, reg_rdata));
+
+ if (val)
-+ v |= BIT(bit_nr);
++ reg |= GPIO_BIT(offset);
+ else
-+ v &= ~BIT(bit_nr);
-+
-+ writel(v, priv->base + priv->data_offset);
++ reg &= ~GPIO_BIT(offset);
+
-+ dev_dbg(priv->dev, "%s, %s[%d]: %d\n", __func__, chip->label,
-+ offset, val);
++ iowrite32(reg, bank_reg(gpio, bank, reg_val));
+
-+ local_irq_restore(flags);
++ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
-+#define SGPIO_BANK(name, index_no, data, read_data, int_en, int_type, \
-+ int_sts, rst_tol, chip_base_idx) { \
-+ .index = index_no, \
-+ .data_offset = data, \
-+ .data_read_offset = read_data, \
-+ .int_en_offset = int_en, \
-+ .int_type_offset = int_type, \
-+ .int_sts_offset = int_sts, \
-+ .rst_tol_offset = rst_tol, \
-+ .chip = { \
-+ .label = name, \
-+ .get = aspeed_sgpio_get, \
-+ .set = aspeed_sgpio_set, \
-+ .base = SGPIO_CHAIN_CHIP_BASE + chip_base_idx * 8, \
-+ .ngpio = GPIOS_PER_PORT, \
-+ }, \
-+}
++static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+
-+// TODO: use a single priv after changing it as an array member of the priv
-+static struct aspeed_sgpio aspeed_sgpio_gp[] = {
-+ SGPIO_BANK("SGPIOA", 0, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 0),
-+ SGPIO_BANK("SGPIOB", 1, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 1),
-+ SGPIO_BANK("SGPIOC", 2, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 2),
-+ SGPIO_BANK("SGPIOD", 3, 0x000, 0x070, 0x004, 0x008, 0x014, 0x018, 3),
-+ SGPIO_BANK("SGPIOE", 0, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 4),
-+ SGPIO_BANK("SGPIOF", 1, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 5),
-+ SGPIO_BANK("SGPIOG", 2, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 6),
-+ SGPIO_BANK("SGPIOH", 3, 0x01C, 0x074, 0x020, 0x024, 0x030, 0x034, 7),
-+ SGPIO_BANK("SGPIOI", 0, 0x038, 0x078, 0x03C, 0x040, 0x04C, 0x050, 8),
-+ SGPIO_BANK("SGPIOJ", 1, 0x038, 0x078, 0x03C, 0x040, 0x04C, 0x050, 9),
-+};
++ if (!have_input(gpio, offset))
++ return -ENOTSUPP;
+
-+/**
-+ * We need to unmask the GPIO bank interrupt as soon as possible to avoid
-+ * missing GPIO interrupts for other lines in the bank. Then we need to
-+ * mask-read-clear-unmask the triggered GPIO lines in the bank to avoid missing
-+ * nested interrupts for a GPIO line. If we wait to unmask individual GPIO lines
-+ * in the bank after the line's interrupt handler has been run, we may miss some
-+ * nested interrupts.
-+ */
-+static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
++ return 0;
++}
++
++static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset,
++ int val)
+{
-+ struct irq_chip *chip = irq_desc_get_chip(desc);
-+ struct aspeed_sgpio *priv = irq_desc_get_chip_data(desc);
-+ u32 isr;
-+ int i;
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+
-+ chained_irq_enter(chip, desc);
++ if (!have_output(gpio, offset))
++ return -ENOTSUPP;
+
-+ isr = readl(priv->base + priv->int_sts_offset);
-+ isr = (isr >> (GPIOS_PER_PORT * priv->index)) & 0xff;
++ return 0;
++}
+
-+ dev_dbg(priv->dev, "[%s] isr %x \n", priv->chip.label, isr);
++static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
++{
++ struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
+
-+ if (isr != 0) {
-+ for (i = 0; i < GPIOS_PER_PORT; i++) {
-+ if (BIT(i) & isr)
-+ generic_handle_irq(i * GPIOS_PER_PORT +
-+ i + IRQ_SGPIO_CHAIN_START);
-+ }
-+ }
++ if (have_output(gpio, offset))
++ return 0;
++ else if (have_input(gpio, offset))
++ return 1;
+
-+ chained_irq_exit(chip, desc);
++ return -ENOTSUPP;
+}
+
-+static void aspeed_sgpio_ack_irq(struct irq_data *d)
++static inline int
++irqd_to_aspeed_sgpio_data(struct irq_data *d, struct aspeed_sgpio **gpio,
++ const struct aspeed_sgpio_bank **bank,
++ u32 *bit, int *offset)
+{
-+ struct aspeed_sgpio *priv = irq_get_chip_data(d->irq);
-+ uint sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
-+ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++ struct aspeed_sgpio *internal;
++
++ *offset = irqd_to_hwirq(d);
++
++ internal = irq_data_get_irq_chip_data(d);
+
-+ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n", d->irq, __func__,
-+ priv->chip.label, sgpio_irq);
++ *gpio = internal;
++ *bank = to_bank(*offset);
++ *bit = GPIO_BIT(*offset);
+
-+ writel(BIT(bit_nr), priv->base + priv->int_sts_offset);
++ return 0;
+}
+
-+static void aspeed_sgpio_mask_irq(struct irq_data *d)
++static void aspeed_sgpio_irq_ack(struct irq_data *d)
+{
-+ struct aspeed_sgpio *priv = irq_get_chip_data(d->irq);
-+ uint sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
-+ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++ const struct aspeed_sgpio_bank *bank;
++ struct aspeed_sgpio *gpio;
++ void __iomem *status_addr;
++ unsigned long flags;
++ int rc, offset;
++ u32 bit;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
++ return;
++
++ status_addr = bank_reg(gpio, bank, reg_irq_status);
++
++ spin_lock_irqsave(&gpio->lock, flags);
+
-+ /* Disable IRQ */
-+ writel(readl(priv->base + priv->int_en_offset) & ~BIT(bit_nr),
-+ priv->base + priv->int_en_offset);
++ iowrite32(bit, status_addr);
+
-+ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n ", d->irq, __func__,
-+ priv->chip.label, sgpio_irq);
++ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
-+static void aspeed_sgpio_unmask_irq(struct irq_data *d)
++static void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
+{
-+ struct aspeed_sgpio *priv = irq_data_get_irq_chip_data(d);
-+ u32 sgpio_irq = (d->irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
-+ uint bit_nr = priv->index * GPIOS_PER_PORT + sgpio_irq;
++ const struct aspeed_sgpio_bank *bank;
++ struct aspeed_sgpio *gpio;
++ unsigned long flags;
++ u32 reg, bit;
++ void __iomem *addr;
++ int rc, offset;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
++ return;
++
++ if (!bank->support_irq)
++ return;
++
++ addr = bank_reg(gpio, bank, reg_irq_enable);
++
++ spin_lock_irqsave(&gpio->lock, flags);
+
-+ /* Enable IRQ */
-+ writel(BIT(bit_nr), priv->base + priv->int_sts_offset);
-+ writel(readl(priv->base + priv->int_en_offset) | BIT(bit_nr),
-+ priv->base + priv->int_en_offset);
++ reg = ioread32(addr);
++ if (set)
++ reg |= bit;
++ else
++ reg &= ~bit;
++
++ iowrite32(reg, addr);
+
-+ dev_dbg(priv->dev, "irq %d: %s [%s] pin %d\n", d->irq, __func__,
-+ priv->chip.label, sgpio_irq);
++ spin_unlock_irqrestore(&gpio->lock, flags);
+}
+
-+static int aspeed_sgpio_irq_type(struct irq_data *d, unsigned int type)
++static void aspeed_sgpio_irq_mask(struct irq_data *d)
+{
-+ unsigned int irq = d->irq;
-+ struct aspeed_sgpio *priv = irq_get_chip_data(irq);
-+ u32 sgpio_irq = (irq - IRQ_SGPIO_CHAIN_START) % GPIOS_PER_PORT;
-+ u32 type0, type1, type2;
++ aspeed_sgpio_irq_set_mask(d, false);
++}
+
-+ dev_dbg(priv->dev, "irq: %d, sgpio_irq: %d , irq_type: 0x%x\n",
-+ irq, sgpio_irq, type);
++static void aspeed_sgpio_irq_unmask(struct irq_data *d)
++{
++ aspeed_sgpio_irq_set_mask(d, true);
++}
+
-+ if (type & ~IRQ_TYPE_SENSE_MASK)
++static int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
++{
++ u32 type0 = 0;
++ u32 type1 = 0;
++ u32 type2 = 0;
++ u32 bit, reg;
++ const struct aspeed_sgpio_bank *bank;
++ irq_flow_handler_t handler;
++ struct aspeed_sgpio *gpio;
++ unsigned long flags;
++ void __iomem *addr;
++ int rc, offset;
++
++ rc = irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
++ if (rc)
+ return -EINVAL;
+
-+ type0 = readl(priv->base + priv->int_type_offset);
-+ type1 = readl(priv->base + priv->int_type_offset + 0x04);
-+ type2 = readl(priv->base + priv->int_type_offset + 0x08);
++ if (!bank->support_irq)
++ return -ENOTSUPP;
+
-+ switch (type) {
-+ /* Edge rising type */
++ switch (type & IRQ_TYPE_SENSE_MASK) {
++ case IRQ_TYPE_EDGE_BOTH:
++ type2 |= bit;
++ /* fall through */
+ case IRQ_TYPE_EDGE_RISING:
-+ type0 |= BIT(sgpio_irq);
-+ type1 &= ~BIT(sgpio_irq);
-+ type2 &= ~BIT(sgpio_irq);
-+ break;
-+ /* Edge falling type */
++ type0 |= bit;
++ /* fall through */
+ case IRQ_TYPE_EDGE_FALLING:
-+ type2 |= BIT(sgpio_irq);
-+ break;
-+ case IRQ_TYPE_EDGE_BOTH:
-+ type0 &= ~BIT(sgpio_irq);
-+ type1 |= BIT(sgpio_irq);
-+ type2 &= ~BIT(sgpio_irq);
++ handler = handle_edge_irq;
+ break;
+ case IRQ_TYPE_LEVEL_HIGH:
-+ type0 |= BIT(sgpio_irq);
-+ type1 |= BIT(sgpio_irq);
-+ type2 &= ~BIT(sgpio_irq);
-+ break;
++ type0 |= bit;
++ /* fall through */
+ case IRQ_TYPE_LEVEL_LOW:
-+ type0 &= ~BIT(sgpio_irq);
-+ type1 |= BIT(sgpio_irq);
-+ type2 &= ~BIT(sgpio_irq);
++ type1 |= bit;
++ handler = handle_level_irq;
+ break;
+ default:
-+ dev_dbg(priv->dev, "not supported trigger type: %d", type);
+ return -EINVAL;
-+ break;
+ }
+
-+ writel(type0, priv->base + priv->int_type_offset);
-+ writel(type1, priv->base + priv->int_type_offset + 0x04);
-+ writel(type2, priv->base + priv->int_type_offset + 0x08);
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ addr = bank_reg(gpio, bank, reg_irq_type0);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type0;
++ iowrite32(reg, addr);
++
++ addr = bank_reg(gpio, bank, reg_irq_type1);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type1;
++ iowrite32(reg, addr);
++
++ addr = bank_reg(gpio, bank, reg_irq_type2);
++ reg = ioread32(addr);
++ reg = (reg & ~bit) | type2;
++ iowrite32(reg, addr);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
++
++ irq_set_handler_locked(d, handler);
+
+ return 0;
+}
+
-+static struct irq_chip aspeed_sgpio_irq_chip = {
-+ .name = "aspeed-sgpio",
-+ .irq_ack = aspeed_sgpio_ack_irq,
-+ .irq_mask = aspeed_sgpio_mask_irq,
-+ .irq_unmask = aspeed_sgpio_unmask_irq,
-+ .irq_set_type = aspeed_sgpio_irq_type,
++static void aspeed_sgpio_irq_handler(struct irq_desc *desc)
++{
++ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
++ struct aspeed_sgpio *data = gpiochip_get_data(gc);
++ struct irq_chip *ic = irq_desc_get_chip(desc);
++ unsigned int i, p, girq;
++ unsigned long reg;
++
++ chained_irq_enter(ic, desc);
++
++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
++ const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
++
++ if (!bank->support_irq)
++ continue;
++
++ reg = ioread32(bank_reg(data, bank, reg_irq_status));
++
++ for_each_set_bit(p, &reg, 32) {
++ girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
++ generic_handle_irq(girq);
++ }
++ }
++
++ chained_irq_exit(ic, desc);
++}
++
++static struct irq_chip aspeed_sgpio_irqchip = {
++ .name = "aspeed-sgpio",
++ .irq_ack = aspeed_sgpio_irq_ack,
++ .irq_mask = aspeed_sgpio_irq_mask,
++ .irq_unmask = aspeed_sgpio_irq_unmask,
++ .irq_set_type = aspeed_sgpio_set_type,
+};
+
-+static int aspeed_sgpio_config(struct aspeed_sgpio *priv)
++static void set_irq_valid_mask(struct aspeed_sgpio *gpio)
+{
-+ /**
-+ * There is a limitation that SGPIO clock division has to be larger or
-+ * equal to 1. And the value of clock division read back is left shift
-+ * 1 bit from actual value.
-+ *
-+ * GPIO254[31:16] - Serial GPIO clock division
-+ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1)
-+ *
-+ * SGPIO master controller updates every data input when SGPMLD is low.
-+ * For example, SGPIO clock is 1MHz and number of SGPIO is 80 then each
-+ * SGPIO will be updated in every 80us.
-+ */
-+ writel(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, 10) |
-+ FIELD_PREP(ASPEED_SGPIO_PINS_MASK, SGPIO_GROUP_NUMS) |
-+ ASPEED_SGPIO_ENABLE,
-+ priv->base + ASPEED_SGPIO_CTRL);
-+ dev_dbg(priv->dev, "sgpio config reg: 0x%08X\n",
-+ readl(priv->base + ASPEED_SGPIO_CTRL));
++ const struct aspeed_bank_props *props = gpio->config->props;
+
-+ return 0;
++ while (!is_bank_props_sentinel(props)) {
++ unsigned int offset;
++ const unsigned long int input = props->input;
++
++ /* Pretty crummy approach, but similar to GPIO core */
++ for_each_clear_bit(offset, &input, 32) {
++ unsigned int i = props->bank * 32 + offset;
++
++ if (i >= gpio->config->nr_gpios)
++ break;
++
++ clear_bit(i, gpio->chip.irq.valid_mask);
++ }
++
++ props++;
++ }
+}
+
-+static int aspeed_sgpio_probe(struct platform_device *pdev)
++static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
++ struct platform_device *pdev)
+{
-+ int i, j;
-+ uint irq;
-+ struct resource *res;
-+ struct aspeed_sgpio *priv;
-+ void __iomem *base;
-+ int mirq;
-+
-+ // aspeed_scu_multi_func_sgpio(); done via pinctl
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ mirq = platform_get_irq(pdev, 0);
-+ if (!mirq)
-+ return -ENODEV;
-+
-+ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_gp); i++) {
-+ // TODO: use heap allocation and use a single priv
-+ priv = &aspeed_sgpio_gp[i];
-+ priv->dev = &pdev->dev;
-+ priv->base = base;
-+ priv->mirq = mirq;
-+ dev_set_drvdata(&pdev->dev, priv);
-+
-+ dev_dbg(priv->dev, "add gpio_chip [%s]: %d\n", priv->chip.label,
-+ i);
-+
-+ devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv);
-+
-+ /* Disable Interrupt & Clear Status & Set Level-High Trigger */
-+ writel(0x00000000, priv->base + priv->int_en_offset);
-+ writel(0xffffffff, priv->base + priv->int_sts_offset);
-+ writel(0xffffffff, priv->base + priv->int_type_offset);
-+ writel(0xffffffff, priv->base + priv->int_type_offset + 0x04);
-+ writel(0x00000000, priv->base + priv->int_type_offset + 0x08);
-+
-+ // TODO: no this many chip registration is needed. fix it.
-+ for (j = 0; j < GPIOS_PER_PORT; j++) {
-+ irq = i * GPIOS_PER_PORT + j + IRQ_SGPIO_CHAIN_START;
-+ dev_dbg(priv->dev, "inst chip data %d\n", irq);
-+ irq_set_chip_data(irq, priv);
-+ irq_set_chip_and_handler(irq, &aspeed_sgpio_irq_chip,
-+ handle_level_irq);
-+ irq_clear_status_flags(irq, IRQ_NOREQUEST);
-+ }
++ const struct aspeed_sgpio_bank *bank;
++ int rc, i;
++
++ /* Initialize IRQ and tolerant settings */
++ for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
++ bank = &aspeed_sgpio_banks[i];
++
++ /* Value will be reset by WDT reset */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_tolerance));
++
++ if (!bank->support_irq)
++ continue;
++
++ /* disable irq enable bits */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
++ /* clear status bits */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
++ /* set rising or level-high irq */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type0));
++ /* trigger type is level */
++ iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type1));
++ /* single trigger mode */
++ iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
+ }
+
-+ irq_set_chained_handler(priv->mirq, aspeed_sgpio_irq_handler);
++ rc = platform_get_irq(pdev, 0);
++ if (rc < 0)
++ return rc;
++
++ gpio->irq = rc;
+
-+ aspeed_sgpio_config(priv);
++ set_irq_valid_mask(gpio);
+
-+ dev_info(&pdev->dev, "sgpio controller registered, irq %d\n",
-+ priv->mirq);
++ rc = gpiochip_irqchip_add(&gpio->chip, &aspeed_sgpio_irqchip,
++ 0, handle_bad_irq, IRQ_TYPE_NONE);
++ if (rc) {
++ dev_info(&pdev->dev, "Could not add irqchip\n");
++ return rc;
++ }
++
++ gpiochip_set_chained_irqchip(&gpio->chip, &aspeed_sgpio_irqchip,
++ gpio->irq, aspeed_sgpio_irq_handler);
+
+ return 0;
+}
+
-+static int aspeed_sgpio_remove(struct platform_device *pdev)
++static int aspeed_sgpio_reset_tolerance(struct gpio_chip *chip,
++ unsigned int offset, bool enable)
+{
-+ struct aspeed_sgpio *priv =
-+ &aspeed_sgpio_gp[ARRAY_SIZE(aspeed_sgpio_gp) - 1];
++ struct aspeed_sgpio *gpio = gpiochip_get_data(chip);
++ unsigned long flags;
++ void __iomem *treg;
++ u32 val;
+
-+ irq_set_chained_handler(priv->mirq, NULL);
++ treg = bank_reg(gpio, to_bank(offset), reg_tolerance);
++
++ spin_lock_irqsave(&gpio->lock, flags);
++
++ val = readl(treg);
++
++ if (enable)
++ val |= GPIO_BIT(offset);
++ else
++ val &= ~GPIO_BIT(offset);
++
++ writel(val, treg);
++
++ spin_unlock_irqrestore(&gpio->lock, flags);
+
+ return 0;
+}
+
++static int aspeed_sgpio_set_config(struct gpio_chip *chip, unsigned int offset,
++ unsigned long config)
++{
++ unsigned long param = pinconf_to_config_param(config);
++ u32 arg = pinconf_to_config_argument(config);
++
++ if (param == PIN_CONFIG_PERSIST_STATE)
++ return aspeed_sgpio_reset_tolerance(chip, offset, arg);
++
++ return -ENOTSUPP;
++}
++
++/*
++ * Any banks not specified in a struct aspeed_bank_props array are assumed to
++ * have the properties:
++ *
++ * { .input = 0xffffffff, .output = 0xffffffff }
++ */
++
++static const struct aspeed_bank_props ast_sgpio_bank_props[] = {
++ /* input output */
++ { 0, 0x00000000, 0xffffffff }, /* OA/OB/OC/OD */
++ { 1, 0x00000000, 0xffffffff }, /* OE/OF/OG/OH */
++ { 2, 0x00000000, 0x0000ffff }, /* OI/OJ */
++ { 3, 0xffffffff, 0x00000000 }, /* IA/IB/IC/ID */
++ { 4, 0xffffffff, 0x00000000 }, /* IE/IF/IG/IH */
++ { 5, 0x0000ffff, 0x00000000 }, /* II/IJ */
++ { }
++};
++
++/*
++ * This H/W has 80 bidirectional lines so this driver provides total 160 lines
++ * for 80 outputs and 80 inputs. To simplify bank register manipulation, it
++ * uses 96 lines per each input and output set so total 192 lines it has.
++ */
++static const struct aspeed_sgpio_config ast2400_config =
++ { .nr_pgpios = 224, .nr_gpios = 192, .props = ast_sgpio_bank_props };
++
++static const struct aspeed_sgpio_config ast2500_config =
++ { .nr_pgpios = 232, .nr_gpios = 192, .props = ast_sgpio_bank_props };
++
+static const struct of_device_id aspeed_sgpio_of_table[] = {
-+ { .compatible = "aspeed,ast2400-sgpio", },
-+ { .compatible = "aspeed,ast2500-sgpio", },
-+ { },
++ { .compatible = "aspeed,ast2400-sgpio", .data = &ast2400_config },
++ { .compatible = "aspeed,ast2500-sgpio", .data = &ast2500_config },
++ { }
+};
+MODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
+
++static int __init aspeed_sgpio_probe(struct platform_device *pdev)
++{
++ const struct of_device_id *gpio_id;
++ u32 sgpio_freq, clk_div, nb_gpios;
++ struct aspeed_sgpio *gpio;
++ unsigned long src_freq;
++ struct clk *clk;
++ int rc, banks;
++
++ gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
++ if (!gpio)
++ return -ENOMEM;
++
++ gpio->base = devm_platform_ioremap_resource(pdev, 0);
++ if (IS_ERR(gpio->base))
++ return PTR_ERR(gpio->base);
++
++ spin_lock_init(&gpio->lock);
++
++ gpio_id = of_match_node(aspeed_sgpio_of_table, pdev->dev.of_node);
++ if (!gpio_id)
++ return -EINVAL;
++
++ gpio->config = gpio_id->data;
++
++ rc = device_property_read_u32(&pdev->dev, "bus-frequency", &sgpio_freq);
++ if (rc < 0) {
++ dev_warn(&pdev->dev, "Could not read bus-frequency property. Use default.\n");
++ sgpio_freq = ASPEED_SGPIO_BUS_FREQ_DEFAULT;
++ }
++
++ clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "Failed to get clk source.\n");
++ return PTR_ERR(clk);
++ }
++
++ /*
++ * There is a limitation that SGPIO clock division has to be larger or
++ * equal to 1. And a read back value of clock division is 1-bit left
++ * shifted from the actual value.
++ *
++ * GPIO254[31:16] - Serial GPIO clock division:
++ * Serial GPIO clock period = period of PCLK * 2 * (GPIO254[31:16] + 1)
++ *
++ * SGPIO master controller updates every data input when SGPMLD is low.
++ * For an example, SGPIO clock is 1MHz and number of SGPIO is 80. Each
++ * SGPIO will be updated every 80us.
++ */
++ src_freq = clk_get_rate(clk);
++ clk_div = src_freq / (2 * sgpio_freq) - 1;
++ if (clk_div < ASPEED_SGPIO_CLK_DIV_MIN)
++ clk_div = ASPEED_SGPIO_CLK_DIV_MIN;
++ else if (clk_div > ASPEED_SGPIO_CLK_DIV_MAX)
++ clk_div = ASPEED_SGPIO_CLK_DIV_MAX;
++
++ nb_gpios = gpio->config->nr_gpios / 16;
++ if (nb_gpios < ASPEED_SGPIO_PINBYTES_MIN)
++ nb_gpios = ASPEED_SGPIO_PINBYTES_MIN;
++ else if (nb_gpios > ASPEED_SGPIO_PINBYTES_MAX)
++ nb_gpios = ASPEED_SGPIO_PINBYTES_MAX;
++
++ iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, clk_div) |
++ FIELD_PREP(ASPEED_SGPIO_PINBYTES_MASK, nb_gpios) |
++ ASPEED_SGPIO_ENABLE,
++ gpio->base + ASPEED_SGPIO_CTRL);
++
++ gpio->chip.parent = &pdev->dev;
++ gpio->chip.ngpio = gpio->config->nr_gpios;
++
++ gpio->chip.direction_input = aspeed_sgpio_dir_in;
++ gpio->chip.direction_output = aspeed_sgpio_dir_out;
++ gpio->chip.get_direction = aspeed_sgpio_get_direction;
++ gpio->chip.get = aspeed_sgpio_get;
++ gpio->chip.set = aspeed_sgpio_set;
++ gpio->chip.set_config = aspeed_sgpio_set_config;
++ gpio->chip.label = dev_name(&pdev->dev);
++ gpio->chip.base = -1;
++ gpio->chip.irq.need_valid_mask = true;
++
++ /* Allocate a cache of the output registers */
++ banks = gpio->config->nr_gpios >> 5;
++
++ gpio->dcache = devm_kcalloc(&pdev->dev,
++ banks, sizeof(u32), GFP_KERNEL);
++
++ if (!gpio->dcache)
++ return -ENOMEM;
++
++ rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
++ if (rc < 0)
++ return rc;
++
++ return aspeed_sgpio_setup_irqs(gpio, pdev);
++}
++
+static struct platform_driver aspeed_sgpio_driver = {
-+ .probe = aspeed_sgpio_probe,
-+ .remove = aspeed_sgpio_remove,
+ .driver = {
-+ .name = "sgpio-aspeed",
-+ .of_match_table = of_match_ptr(aspeed_sgpio_of_table),
++ .name = KBUILD_MODNAME,
++ .of_match_table = aspeed_sgpio_of_table,
+ },
+};
+
-+static int __init aspeed_sgpio_init(void)
-+{
-+ return platform_driver_register(&aspeed_sgpio_driver);
-+}
-+subsys_initcall(aspeed_sgpio_init);
-+
-+static void __exit aspeed_sgpio_exit(void)
-+{
-+ platform_driver_unregister(&aspeed_sgpio_driver);
-+}
-+module_exit(aspeed_sgpio_exit);
++module_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
+
-+MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
+MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
-+MODULE_DESCRIPTION("ASPEED SGPIO driver");
++MODULE_DESCRIPTION("Aspeed SGPIO Master Driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch
index 8083ead0b..4210d9f67 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0009-SGPIO-DT-and-pinctrl-fixup.patch
@@ -1,4 +1,4 @@
-From 1059e64f4fc5af65f2afdc209761342fe44e3498 Mon Sep 17 00:00:00 2001
+From 0f63ecc25766fdf66610d08441e59147a4cbde78 Mon Sep 17 00:00:00 2001
From: Vernon Mauery <vernon.mauery@intel.com>
Date: Wed, 16 May 2018 10:03:14 -0700
Subject: [PATCH] SGPIO DT and pinctrl fixup
@@ -8,17 +8,17 @@ This commit fixes DT and pinctrl for SGPIO use.
Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
- arch/arm/boot/dts/aspeed-g4.dtsi | 54 ++++++++++--------------------
- arch/arm/boot/dts/aspeed-g5.dtsi | 8 +++++
- drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 +++++++++++++-------------
+ arch/arm/boot/dts/aspeed-g4.dtsi | 56 +++++++++++-------------------
+ arch/arm/boot/dts/aspeed-g5.dtsi | 10 ++++++
+ drivers/pinctrl/aspeed/pinctrl-aspeed-g4.c | 48 ++++++++++++-------------
drivers/pinctrl/aspeed/pinctrl-aspeed-g5.c | 4 +++
- 4 files changed, 54 insertions(+), 60 deletions(-)
+ 4 files changed, 58 insertions(+), 60 deletions(-)
diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
-index fd857be397bf..00848693f455 100644
+index fd857be397bf..58306a8232c9 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
-@@ -207,6 +207,18 @@
+@@ -207,6 +207,20 @@
#interrupt-cells = <2>;
};
@@ -29,6 +29,8 @@ index fd857be397bf..00848693f455 100644
+ reg = <0x1e780200 0x0100>;
+ interrupts = <40>;
+ interrupt-controller;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ bus-frequency = <1000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgpm_default>;
+ status = "disabled";
@@ -37,7 +39,7 @@ index fd857be397bf..00848693f455 100644
timer: timer@1e782000 {
/* This timer is a Faraday FTTMR010 derivative */
compatible = "aspeed,ast2400-timer";
-@@ -1180,44 +1192,14 @@
+@@ -1180,44 +1194,14 @@
groups = "SD2";
};
@@ -89,20 +91,22 @@ index fd857be397bf..00848693f455 100644
pinctrl_sioonctrl_default: sioonctrl_default {
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
-index db82f47339aa..8406da6f62a5 100644
+index db82f47339aa..425a542690de 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
-@@ -298,6 +298,9 @@
+@@ -298,6 +298,11 @@
reg = <0x1e780200 0x0100>;
interrupts = <40>;
interrupt-controller;
++ clocks = <&syscon ASPEED_CLK_APB>;
++ bus-frequency = <1000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgpm_default>;
+ status = "disabled";
};
rtc: rtc@1e781000 {
-@@ -1403,6 +1406,11 @@
+@@ -1403,6 +1408,11 @@
groups = "SDA2";
};
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
index 86dd2e68c..329a92cd6 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0010-Update-PECI-drivers-to-sync-with-linux-upstreaming-v.patch
@@ -1,4 +1,4 @@
-From 2dec2c142e48a35e6c7de00c6a35e963de7447e0 Mon Sep 17 00:00:00 2001
+From 691b8580a1592eddb919e8dd295e6c1f136a4c00 Mon Sep 17 00:00:00 2001
From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
Date: Mon, 7 Jan 2019 09:56:10 -0800
Subject: [PATCH] Update PECI drivers to sync with linux upstreaming version
@@ -10,25 +10,25 @@ Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
---
Documentation/hwmon/peci-cputemp | 34 +-
drivers/hwmon/Kconfig | 4 +-
- drivers/hwmon/peci-cputemp.c | 162 ++++--
- drivers/hwmon/peci-dimmtemp.c | 69 +--
+ drivers/hwmon/peci-cputemp.c | 171 ++++---
+ drivers/hwmon/peci-dimmtemp.c | 184 +++++--
drivers/hwmon/peci-hwmon.h | 9 +-
drivers/mfd/Kconfig | 5 +-
- drivers/mfd/intel-peci-client.c | 49 +-
+ drivers/mfd/intel-peci-client.c | 51 +-
drivers/peci/Kconfig | 46 +-
drivers/peci/Makefile | 7 +-
drivers/peci/busses/Kconfig | 32 ++
drivers/peci/busses/Makefile | 7 +
- drivers/peci/busses/peci-aspeed.c | 494 +++++++++++++++++++
+ drivers/peci/busses/peci-aspeed.c | 492 ++++++++++++++++++
drivers/peci/busses/peci-npcm.c | 410 +++++++++++++++
drivers/peci/peci-aspeed.c | 505 -------------------
- drivers/peci/peci-core.c | 905 +++++++++++++++++++---------------
+ drivers/peci/peci-core.c | 914 ++++++++++++++++++----------------
drivers/peci/peci-dev.c | 346 +++++++++++++
drivers/peci/peci-npcm.c | 410 ---------------
- include/linux/mfd/intel-peci-client.h | 32 +-
+ include/linux/mfd/intel-peci-client.h | 31 +-
include/linux/peci.h | 30 +-
include/uapi/linux/peci-ioctl.h | 416 +++++++++-------
- 20 files changed, 2296 insertions(+), 1676 deletions(-)
+ 20 files changed, 2402 insertions(+), 1702 deletions(-)
create mode 100644 drivers/peci/busses/Kconfig
create mode 100644 drivers/peci/busses/Makefile
create mode 100644 drivers/peci/busses/peci-aspeed.c
@@ -115,7 +115,7 @@ index c0623fa5ba41..7399c3cef30c 100644
source "drivers/hwmon/pmbus/Kconfig"
diff --git a/drivers/hwmon/peci-cputemp.c b/drivers/hwmon/peci-cputemp.c
-index 11880c86a854..3cb2db2fdf0a 100644
+index 11880c86a854..d0d68e88889f 100644
--- a/drivers/hwmon/peci-cputemp.c
+++ b/drivers/hwmon/peci-cputemp.c
@@ -1,5 +1,5 @@
@@ -125,7 +125,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
#include <linux/hwmon.h>
#include <linux/jiffies.h>
-@@ -9,7 +9,7 @@
+@@ -9,18 +9,13 @@
#include <linux/platform_device.h>
#include "peci-hwmon.h"
@@ -134,15 +134,19 @@ index 11880c86a854..3cb2db2fdf0a 100644
#define CORETEMP_CHANNEL_NUMS CORE_NUMS_MAX
#define CPUTEMP_CHANNEL_NUMS (DEFAULT_CHANNEL_NUMS + CORETEMP_CHANNEL_NUMS)
-@@ -21,6 +21,7 @@
-
+-/* The RESOLVED_CORES register in PCU of a client CPU */
+-#define REG_RESOLVED_CORES_BUS 1
+-#define REG_RESOLVED_CORES_DEVICE 30
+-#define REG_RESOLVED_CORES_FUNCTION 3
+-#define REG_RESOLVED_CORES_OFFSET 0xB4
+-
struct temp_group {
struct temp_data die;
+ struct temp_data dts;
struct temp_data tcontrol;
struct temp_data tthrottle;
struct temp_data tjmax;
-@@ -43,6 +44,7 @@ struct peci_cputemp {
+@@ -43,6 +38,7 @@ struct peci_cputemp {
enum cputemp_channels {
channel_die,
@@ -150,7 +154,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
channel_tcontrol,
channel_tthrottle,
channel_tjmax,
-@@ -54,6 +56,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+@@ -54,6 +50,10 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT |
HWMON_T_CRIT_HYST,
@@ -161,7 +165,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
/* Tcontrol temperature */
HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT,
-@@ -70,6 +76,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
+@@ -70,6 +70,7 @@ static const u32 config_table[DEFAULT_CHANNEL_NUMS + 1] = {
static const char *cputemp_label[CPUTEMP_CHANNEL_NUMS] = {
"Die",
@@ -169,7 +173,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
"Tcontrol",
"Tthrottle",
"Tjmax",
-@@ -92,19 +99,20 @@ static int get_temp_targets(struct peci_cputemp *priv)
+@@ -92,19 +93,20 @@ static int get_temp_targets(struct peci_cputemp *priv)
s32 tthrottle_offset;
s32 tcontrol_margin;
u8 pkg_cfg[4];
@@ -196,7 +200,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
priv->temp.tjmax.value = pkg_cfg[2] * 1000;
-@@ -123,17 +131,16 @@ static int get_temp_targets(struct peci_cputemp *priv)
+@@ -123,17 +125,16 @@ static int get_temp_targets(struct peci_cputemp *priv)
static int get_die_temp(struct peci_cputemp *priv)
{
struct peci_get_temp_msg msg;
@@ -218,33 +222,27 @@ index 11880c86a854..3cb2db2fdf0a 100644
/* Note that the tjmax should be available before calling it */
priv->temp.die.value = priv->temp.tjmax.value +
-@@ -144,24 +151,70 @@ static int get_die_temp(struct peci_cputemp *priv)
+@@ -144,24 +145,64 @@ static int get_die_temp(struct peci_cputemp *priv)
return 0;
}
+static int get_dts(struct peci_cputemp *priv)
+{
-+ struct peci_rd_pkg_cfg_msg msg;
+ s32 dts_margin;
++ u8 pkg_cfg[4];
+ int ret;
+
+ if (!peci_temp_need_update(&priv->temp.dts))
+ return 0;
+
-+ msg.addr = priv->mgr->client->addr;
-+ msg.index = PECI_MBX_INDEX_DTS_MARGIN;
-+ msg.param = 0;
-+ msg.rx_len = 4;
++ ret = peci_client_read_package_config(priv->mgr,
++ PECI_MBX_INDEX_DTS_MARGIN, 0,
++ pkg_cfg);
+
-+ ret = peci_command(priv->mgr->client->adapter, PECI_CMD_RD_PKG_CFG,
-+ &msg);
+ if (ret)
+ return ret;
+
-+ if (msg.cc != PECI_DEV_CC_SUCCESS)
-+ return -EAGAIN;
-+
-+ dts_margin = (msg.pkg_config[1] << 8) | msg.pkg_config[0];
++ dts_margin = (pkg_cfg[1] << 8) | pkg_cfg[0];
+
+ /**
+ * Processors return a value of DTS reading in 10.6 format
@@ -296,7 +294,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
* Processors return a value of the core DTS reading in 10.6 format
* (10 bits signed decimal, 6 bits fractional).
* Error codes:
-@@ -192,6 +245,7 @@ static int cputemp_read_string(struct device *dev,
+@@ -192,6 +233,7 @@ static int cputemp_read_string(struct device *dev,
return -EOPNOTSUPP;
*str = cputemp_label[channel];
@@ -304,7 +302,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
return 0;
}
-@@ -200,26 +254,33 @@ static int cputemp_read(struct device *dev,
+@@ -200,26 +242,33 @@ static int cputemp_read(struct device *dev,
u32 attr, int channel, long *val)
{
struct peci_cputemp *priv = dev_get_drvdata(dev);
@@ -344,7 +342,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
case channel_tcontrol:
*val = priv->temp.tcontrol.value;
break;
-@@ -231,8 +292,8 @@ static int cputemp_read(struct device *dev,
+@@ -231,8 +280,8 @@ static int cputemp_read(struct device *dev,
break;
default:
core_index = channel - DEFAULT_CHANNEL_NUMS;
@@ -355,7 +353,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
break;
*val = priv->temp.core[core_index].value;
-@@ -249,11 +310,11 @@ static int cputemp_read(struct device *dev,
+@@ -249,11 +298,11 @@ static int cputemp_read(struct device *dev,
*val = priv->temp.tjmax.value - priv->temp.tcontrol.value;
break;
default:
@@ -369,7 +367,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
}
static umode_t cputemp_is_visible(const void *data,
-@@ -262,11 +323,11 @@ static umode_t cputemp_is_visible(const void *data,
+@@ -262,11 +311,11 @@ static umode_t cputemp_is_visible(const void *data,
{
const struct peci_cputemp *priv = data;
@@ -386,7 +384,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
return 0;
}
-@@ -280,7 +341,7 @@ static const struct hwmon_ops cputemp_ops = {
+@@ -280,40 +329,43 @@ static const struct hwmon_ops cputemp_ops = {
static int check_resolved_cores(struct peci_cputemp *priv)
{
struct peci_rd_pci_cfg_local_msg msg;
@@ -395,8 +393,14 @@ index 11880c86a854..3cb2db2fdf0a 100644
/* Get the RESOLVED_CORES register value */
msg.addr = priv->mgr->client->addr;
-@@ -290,30 +351,34 @@ static int check_resolved_cores(struct peci_cputemp *priv)
- msg.reg = REG_RESOLVED_CORES_OFFSET;
+- msg.bus = REG_RESOLVED_CORES_BUS;
+- msg.device = REG_RESOLVED_CORES_DEVICE;
+- msg.function = REG_RESOLVED_CORES_FUNCTION;
+- msg.reg = REG_RESOLVED_CORES_OFFSET;
++ msg.bus = 1;
++ msg.device = 30;
++ msg.function = 3;
++ msg.reg = 0xb4;
msg.rx_len = 4;
- rc = peci_command(priv->mgr->client->adapter,
@@ -405,11 +409,10 @@ index 11880c86a854..3cb2db2fdf0a 100644
- return rc;
+ ret = peci_command(priv->mgr->client->adapter,
+ PECI_CMD_RD_PCI_CFG_LOCAL, &msg);
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
+ if (ret)
+ return ret;
-+
-+ if (msg.cc != PECI_DEV_CC_SUCCESS)
-+ return -EAGAIN;
priv->core_mask = le32_to_cpup((__le32 *)msg.pci_config);
if (!priv->core_mask)
@@ -439,7 +442,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
priv->temp_config[priv->config_idx++] =
config_table[channel_core];
-@@ -326,7 +391,7 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+@@ -326,7 +378,7 @@ static int peci_cputemp_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct peci_cputemp *priv;
struct device *hwmon_dev;
@@ -448,7 +451,7 @@ index 11880c86a854..3cb2db2fdf0a 100644
if ((mgr->client->adapter->cmd_mask &
(BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
-@@ -346,12 +411,13 @@ static int peci_cputemp_probe(struct platform_device *pdev)
+@@ -346,12 +398,13 @@ static int peci_cputemp_probe(struct platform_device *pdev)
mgr->client->addr - PECI_BASE_ADDR);
priv->temp_config[priv->config_idx++] = config_table[channel_die];
@@ -464,8 +467,17 @@ index 11880c86a854..3cb2db2fdf0a 100644
dev_dbg(dev, "Skipped creating core temp info\n");
priv->chip.ops = &cputemp_ops;
+@@ -385,7 +438,7 @@ MODULE_DEVICE_TABLE(platform, peci_cputemp_ids);
+ static struct platform_driver peci_cputemp_driver = {
+ .probe = peci_cputemp_probe,
+ .id_table = peci_cputemp_ids,
+- .driver = { .name = "peci-cputemp", },
++ .driver = { .name = KBUILD_MODNAME, },
+ };
+ module_platform_driver(peci_cputemp_driver);
+
diff --git a/drivers/hwmon/peci-dimmtemp.c b/drivers/hwmon/peci-dimmtemp.c
-index 86a45a90805b..e088366fd138 100644
+index 86a45a90805b..a404b6ea4ba3 100644
--- a/drivers/hwmon/peci-dimmtemp.c
+++ b/drivers/hwmon/peci-dimmtemp.c
@@ -1,5 +1,5 @@
@@ -475,9 +487,20 @@ index 86a45a90805b..e088366fd138 100644
#include <linux/hwmon.h>
#include <linux/jiffies.h>
-@@ -45,16 +45,16 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+@@ -21,6 +21,8 @@ struct peci_dimmtemp {
+ struct workqueue_struct *work_queue;
+ struct delayed_work work_handler;
+ struct temp_data temp[DIMM_NUMS_MAX];
++ long temp_max[DIMM_NUMS_MAX];
++ long temp_crit[DIMM_NUMS_MAX];
+ u32 dimm_mask;
+ int retry_count;
+ u32 temp_config[DIMM_NUMS_MAX + 1];
+@@ -44,20 +46,106 @@ static int get_dimm_temp(struct peci_dimmtemp *priv, int dimm_no)
+ {
int dimm_order = dimm_no % priv->gen_info->dimm_idx_max;
int chan_rank = dimm_no / priv->gen_info->dimm_idx_max;
++ struct peci_rd_pci_cfg_local_msg rp_msg;
u8 cfg_data[4];
- int rc;
+ int ret;
@@ -498,7 +521,95 @@ index 86a45a90805b..e088366fd138 100644
priv->temp[dimm_no].value = cfg_data[dimm_order] * 1000;
-@@ -77,6 +77,7 @@ static int dimmtemp_read_string(struct device *dev,
++ switch (priv->gen_info->model) {
++ case INTEL_FAM6_SKYLAKE_X:
++ rp_msg.addr = priv->mgr->client->addr;
++ rp_msg.bus = 2;
++ /*
++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0
++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1
++ * Device 11, Function 2: IMC 0 channel 2 -> rank 2
++ * Device 12, Function 2: IMC 1 channel 0 -> rank 3
++ * Device 12, Function 6: IMC 1 channel 1 -> rank 4
++ * Device 13, Function 2: IMC 1 channel 2 -> rank 5
++ */
++ rp_msg.device = 10 + chan_rank / 3 * 2 +
++ (chan_rank % 3 == 2 ? 1 : 0);
++ rp_msg.function = chan_rank % 3 == 1 ? 6 : 2;
++ rp_msg.reg = 0x120 + dimm_order * 4;
++ rp_msg.rx_len = 4;
++
++ ret = peci_command(priv->mgr->client->adapter,
++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
++ if (ret)
++ return ret;
++
++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
++ break;
++ case INTEL_FAM6_SKYLAKE_XD:
++ rp_msg.addr = priv->mgr->client->addr;
++ rp_msg.bus = 2;
++ /*
++ * Device 10, Function 2: IMC 0 channel 0 -> rank 0
++ * Device 10, Function 6: IMC 0 channel 1 -> rank 1
++ * Device 12, Function 2: IMC 1 channel 0 -> rank 2
++ * Device 12, Function 6: IMC 1 channel 1 -> rank 3
++ */
++ rp_msg.device = 10 + chan_rank / 2 * 2;
++ rp_msg.function = chan_rank % 2 ? 6 : 2;
++ rp_msg.reg = 0x120 + dimm_order * 4;
++ rp_msg.rx_len = 4;
++
++ ret = peci_command(priv->mgr->client->adapter,
++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
++ if (ret)
++ return ret;
++
++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
++ break;
++ case INTEL_FAM6_HASWELL_X:
++ case INTEL_FAM6_BROADWELL_X:
++ rp_msg.addr = priv->mgr->client->addr;
++ rp_msg.bus = 1;
++ /*
++ * Device 20, Function 0: IMC 0 channel 0 -> rank 0
++ * Device 20, Function 1: IMC 0 channel 1 -> rank 1
++ * Device 21, Function 0: IMC 0 channel 2 -> rank 2
++ * Device 21, Function 1: IMC 0 channel 3 -> rank 3
++ * Device 23, Function 0: IMC 1 channel 0 -> rank 4
++ * Device 23, Function 1: IMC 1 channel 1 -> rank 5
++ * Device 24, Function 0: IMC 1 channel 2 -> rank 6
++ * Device 24, Function 1: IMC 1 channel 3 -> rank 7
++ */
++ rp_msg.device = 20 + chan_rank / 2 + chan_rank / 4;
++ rp_msg.function = chan_rank % 2;
++ rp_msg.reg = 0x120 + dimm_order * 4;
++ rp_msg.rx_len = 4;
++
++ ret = peci_command(priv->mgr->client->adapter,
++ PECI_CMD_RD_PCI_CFG_LOCAL, &rp_msg);
++ if (rp_msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
++ if (ret)
++ return ret;
++
++ priv->temp_max[dimm_no] = rp_msg.pci_config[1] * 1000;
++ priv->temp_crit[dimm_no] = rp_msg.pci_config[2] * 1000;
++ break;
++ default:
++ return -EOPNOTSUPP;
++ }
++
+ peci_temp_mark_updated(&priv->temp[dimm_no]);
+
+ return 0;
+@@ -77,6 +165,7 @@ static int dimmtemp_read_string(struct device *dev,
chan_rank = channel / dimm_idx_max;
dimm_idx = channel % dimm_idx_max;
*str = dimmtemp_label[chan_rank][dimm_idx];
@@ -506,29 +617,46 @@ index 86a45a90805b..e088366fd138 100644
return 0;
}
-@@ -84,16 +85,17 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
+@@ -84,17 +173,28 @@ static int dimmtemp_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct peci_dimmtemp *priv = dev_get_drvdata(dev);
- int rc;
-+ int ret;
-
- if (attr != hwmon_temp_input)
- return -EOPNOTSUPP;
-
+-
+- if (attr != hwmon_temp_input)
+- return -EOPNOTSUPP;
+-
- rc = get_dimm_temp(priv, channel);
- if (rc)
- return rc;
++ int ret;
++
+ ret = get_dimm_temp(priv, channel);
+ if (ret)
+ return ret;
-
- *val = priv->temp[channel].value;
+
- return 0;
++ switch (attr) {
++ case hwmon_temp_input:
++ *val = priv->temp[channel].value;
++ break;
++ case hwmon_temp_max:
++ *val = priv->temp_max[channel];
++ break;
++ case hwmon_temp_crit:
++ *val = priv->temp_crit[channel];
++ break;
++ default:
++ ret = -EOPNOTSUPP;
++ break;
++ }
+
+- *val = priv->temp[channel].value;
+- return 0;
++ return ret;
}
-@@ -120,16 +122,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
+ static umode_t dimmtemp_is_visible(const void *data,
+@@ -120,16 +220,16 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
{
u32 chan_rank_max = priv->gen_info->chan_rank_max;
u32 dimm_idx_max = priv->gen_info->dimm_idx_max;
@@ -551,7 +679,7 @@ index 86a45a90805b..e088366fd138 100644
}
for (dimm_idx = 0; dimm_idx < dimm_idx_max; dimm_idx++)
-@@ -143,17 +145,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
+@@ -143,17 +243,18 @@ static int check_populated_dimms(struct peci_dimmtemp *priv)
return -EAGAIN;
dev_dbg(priv->dev, "Scanned populated DIMMs: 0x%x\n", priv->dimm_mask);
@@ -574,7 +702,7 @@ index 86a45a90805b..e088366fd138 100644
if (priv->retry_count < DIMM_MASK_CHECK_RETRY_MAX) {
queue_delayed_work(priv->work_queue,
&priv->work_handler,
-@@ -164,11 +167,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+@@ -164,11 +265,11 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
} else {
dev_err(priv->dev,
"Timeout DIMM temp info creation\n");
@@ -588,7 +716,17 @@ index 86a45a90805b..e088366fd138 100644
}
channels = priv->gen_info->chan_rank_max *
-@@ -192,12 +195,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+@@ -177,7 +278,8 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
+ if (priv->dimm_mask & BIT(i))
+ while (i >= config_idx)
+ priv->temp_config[config_idx++] =
+- HWMON_T_LABEL | HWMON_T_INPUT;
++ HWMON_T_LABEL | HWMON_T_INPUT |
++ HWMON_T_MAX | HWMON_T_CRIT;
+
+ priv->chip.ops = &dimmtemp_ops;
+ priv->chip.info = priv->info;
+@@ -192,12 +294,12 @@ static int create_dimm_temp_info(struct peci_dimmtemp *priv)
priv,
&priv->chip,
NULL);
@@ -604,7 +742,7 @@ index 86a45a90805b..e088366fd138 100644
}
static void create_dimm_temp_info_delayed(struct work_struct *work)
-@@ -205,10 +208,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work)
+@@ -205,10 +307,10 @@ static void create_dimm_temp_info_delayed(struct work_struct *work)
struct delayed_work *dwork = to_delayed_work(work);
struct peci_dimmtemp *priv = container_of(dwork, struct peci_dimmtemp,
work_handler);
@@ -618,7 +756,7 @@ index 86a45a90805b..e088366fd138 100644
dev_dbg(priv->dev, "Failed to create DIMM temp info\n");
}
-@@ -217,7 +220,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+@@ -217,7 +319,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
struct peci_client_manager *mgr = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct peci_dimmtemp *priv;
@@ -627,7 +765,7 @@ index 86a45a90805b..e088366fd138 100644
if ((mgr->client->adapter->cmd_mask &
(BIT(PECI_CMD_GET_TEMP) | BIT(PECI_CMD_RD_PKG_CFG))) !=
-@@ -242,8 +245,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+@@ -242,8 +344,8 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&priv->work_handler, create_dimm_temp_info_delayed);
@@ -638,7 +776,7 @@ index 86a45a90805b..e088366fd138 100644
dev_err(dev, "Failed to create DIMM temp info\n");
goto err_free_wq;
}
-@@ -252,7 +255,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
+@@ -252,7 +354,7 @@ static int peci_dimmtemp_probe(struct platform_device *pdev)
err_free_wq:
destroy_workqueue(priv->work_queue);
@@ -647,6 +785,15 @@ index 86a45a90805b..e088366fd138 100644
}
static int peci_dimmtemp_remove(struct platform_device *pdev)
+@@ -275,7 +377,7 @@ static struct platform_driver peci_dimmtemp_driver = {
+ .probe = peci_dimmtemp_probe,
+ .remove = peci_dimmtemp_remove,
+ .id_table = peci_dimmtemp_ids,
+- .driver = { .name = "peci-dimmtemp", },
++ .driver = { .name = KBUILD_MODNAME, },
+ };
+ module_platform_driver(peci_dimmtemp_driver);
+
diff --git a/drivers/hwmon/peci-hwmon.h b/drivers/hwmon/peci-hwmon.h
index 6ca1855a86bb..ce6b470eae63 100644
--- a/drivers/hwmon/peci-hwmon.h
@@ -696,7 +843,7 @@ index 75dbcc7da87c..6f7ee4dd08f6 100644
bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support"
depends on SA1100_H3100 || SA1100_H3600
diff --git a/drivers/mfd/intel-peci-client.c b/drivers/mfd/intel-peci-client.c
-index d53e4f1078ac..466085fd43b9 100644
+index d53e4f1078ac..18bf0af0e09e 100644
--- a/drivers/mfd/intel-peci-client.c
+++ b/drivers/mfd/intel-peci-client.c
@@ -1,12 +1,12 @@
@@ -727,7 +874,7 @@ index d53e4f1078ac..466085fd43b9 100644
static struct mfd_cell peci_functions[] = {
{ .name = "peci-cputemp", },
{ .name = "peci-dimmtemp", },
-@@ -31,19 +25,25 @@ static struct mfd_cell peci_functions[] = {
+@@ -31,38 +25,45 @@ static struct mfd_cell peci_functions[] = {
};
static const struct cpu_gen_info cpu_gen_info_table[] = {
@@ -746,17 +893,19 @@ index d53e4f1078ac..466085fd43b9 100644
.chan_rank_max = CHAN_RANK_MAX_ON_BDX,
.dimm_idx_max = DIMM_IDX_MAX_ON_BDX },
- [CPU_GEN_SKX] = {
-+ { /* Broadwell Xeon D */
-+ .family = 6, /* Family code */
-+ .model = INTEL_FAM6_BROADWELL_XEON_D,
-+ .core_max = CORE_MAX_ON_XD,
-+ .chan_rank_max = CHAN_RANK_MAX_ON_XD,
-+ .dimm_idx_max = DIMM_IDX_MAX_ON_XD },
+ { /* Skylake Xeon */
.family = 6, /* Family code */
.model = INTEL_FAM6_SKYLAKE_X,
.core_max = CORE_MAX_ON_SKX,
-@@ -53,16 +53,17 @@ static const struct cpu_gen_info cpu_gen_info_table[] = {
+ .chan_rank_max = CHAN_RANK_MAX_ON_SKX,
+ .dimm_idx_max = DIMM_IDX_MAX_ON_SKX },
++ { /* Skylake Xeon D */
++ .family = 6, /* Family code */
++ .model = INTEL_FAM6_SKYLAKE_XD,
++ .core_max = CORE_MAX_ON_SKXD,
++ .chan_rank_max = CHAN_RANK_MAX_ON_SKXD,
++ .dimm_idx_max = DIMM_IDX_MAX_ON_SKXD },
+ };
static int peci_client_get_cpu_gen_info(struct peci_client_manager *priv)
{
@@ -830,6 +979,15 @@ index d53e4f1078ac..466085fd43b9 100644
static const struct peci_device_id peci_client_ids[] = {
{ .name = "peci-client" },
+@@ -139,7 +138,7 @@ static struct peci_driver peci_client_driver = {
+ .probe = peci_client_probe,
+ .id_table = peci_client_ids,
+ .driver = {
+- .name = "peci-client",
++ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(peci_client_of_table),
+ },
+ };
diff --git a/drivers/peci/Kconfig b/drivers/peci/Kconfig
index 7293108fb543..9752feee2454 100644
--- a/drivers/peci/Kconfig
@@ -972,10 +1130,10 @@ index 000000000000..aa8ce3ae5947
+obj-$(CONFIG_PECI_NPCM) += peci-npcm.o
diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c
new file mode 100644
-index 000000000000..8a0dd40730cc
+index 000000000000..851b71e32eac
--- /dev/null
+++ b/drivers/peci/busses/peci-aspeed.c
-@@ -0,0 +1,494 @@
+@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2012-2017 ASPEED Technology Inc.
+// Copyright (c) 2018-2019 Intel Corporation
@@ -1371,7 +1529,6 @@ index 000000000000..8a0dd40730cc
+{
+ struct peci_adapter *adapter;
+ struct aspeed_peci *priv;
-+ struct resource *res;
+ int ret;
+
+ adapter = peci_alloc_adapter(&pdev->dev, sizeof(*priv));
@@ -1383,8 +1540,7 @@ index 000000000000..8a0dd40730cc
+ priv->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, priv);
+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ priv->base = devm_ioremap_resource(&pdev->dev, res);
++ priv->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto err_put_adapter_dev;
@@ -1413,7 +1569,7 @@ index 000000000000..8a0dd40730cc
+ priv->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->rst)) {
+ dev_err(&pdev->dev,
-+ "missing or invalid reset controller entry");
++ "missing or invalid reset controller entry\n");
+ ret = PTR_ERR(priv->rst);
+ goto err_put_adapter_dev;
+ }
@@ -1460,7 +1616,7 @@ index 000000000000..8a0dd40730cc
+ .probe = aspeed_peci_probe,
+ .remove = aspeed_peci_remove,
+ .driver = {
-+ .name = "peci-aspeed",
++ .name = KBUILD_MODNAME,
+ .of_match_table = of_match_ptr(aspeed_peci_of_table),
+ },
+};
@@ -2398,7 +2554,7 @@ index 51cb2563ceb6..000000000000
-MODULE_DESCRIPTION("ASPEED PECI driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
-index 6f241469ec7e..d1f0df8b139a 100644
+index 6f241469ec7e..48f29de09311 100644
--- a/drivers/peci/peci-core.c
+++ b/drivers/peci/peci-core.c
@@ -1,38 +1,31 @@
@@ -3400,7 +3556,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
static int peci_check_addr_validity(u8 addr)
{
-@@ -814,18 +907,23 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p)
+@@ -814,18 +907,22 @@ static int peci_check_client_busy(struct device *dev, void *client_new_p)
int peci_get_cpu_id(struct peci_adapter *adapter, u8 addr, u32 *cpu_id)
{
struct peci_rd_pkg_cfg_msg msg;
@@ -3418,12 +3574,11 @@ index 6f241469ec7e..d1f0df8b139a 100644
- if (!rc)
- *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
+ ret = peci_command(adapter, PECI_CMD_RD_PKG_CFG, &msg);
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
-+ if (msg.cc != PECI_DEV_CC_SUCCESS)
-+ return -EAGAIN;
-+
+ *cpu_id = le32_to_cpup((__le32 *)msg.pkg_config);
- return rc;
@@ -3431,7 +3586,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
}
EXPORT_SYMBOL_GPL(peci_get_cpu_id);
-@@ -833,7 +931,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+@@ -833,7 +930,7 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
struct peci_board_info const *info)
{
struct peci_client *client;
@@ -3440,7 +3595,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/* Increase reference count for the adapter assigned */
if (!peci_get_adapter(adapter->nr))
-@@ -847,46 +945,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
+@@ -847,46 +944,49 @@ static struct peci_client *peci_new_device(struct peci_adapter *adapter,
client->addr = info->addr;
strlcpy(client->name, info->type, sizeof(client->name));
@@ -3502,7 +3657,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
return NULL;
}
-@@ -895,8 +996,10 @@ static void peci_unregister_device(struct peci_client *client)
+@@ -895,8 +995,10 @@ static void peci_unregister_device(struct peci_client *client)
if (!client)
return;
@@ -3514,7 +3669,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
device_unregister(&client->dev);
}
-@@ -916,7 +1019,7 @@ static void peci_adapter_dev_release(struct device *dev)
+@@ -916,7 +1018,7 @@ static void peci_adapter_dev_release(struct device *dev)
dev_dbg(dev, "%s: %s\n", __func__, adapter->name);
mutex_destroy(&adapter->userspace_clients_lock);
@@ -3523,7 +3678,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
kfree(adapter);
}
-@@ -928,7 +1031,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -928,7 +1030,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
struct peci_board_info info = {};
struct peci_client *client;
char *blank, end;
@@ -3533,7 +3688,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/* Parse device type */
blank = strchr(buf, ' ');
-@@ -943,16 +1047,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -943,16 +1046,17 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
memcpy(info.type, buf, blank - buf);
/* Parse remaining parameters, reject extra parameters */
@@ -3554,7 +3709,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
client = peci_new_device(adapter, &info);
if (!client)
return -EINVAL;
-@@ -961,8 +1066,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
+@@ -961,8 +1065,8 @@ static ssize_t peci_sysfs_new_device(struct device *dev,
mutex_lock(&adapter->userspace_clients_lock);
list_add_tail(&client->detected, &adapter->userspace_clients);
mutex_unlock(&adapter->userspace_clients_lock);
@@ -3565,7 +3720,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
return count;
}
-@@ -975,9 +1080,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+@@ -975,9 +1079,9 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
struct peci_adapter *adapter = to_peci_adapter(dev);
struct peci_client *client, *next;
struct peci_board_info info = {};
@@ -3577,7 +3732,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/* Parse device type */
blank = strchr(buf, ' ');
-@@ -992,41 +1097,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
+@@ -992,41 +1096,41 @@ static ssize_t peci_sysfs_delete_device(struct device *dev,
memcpy(info.type, buf, blank - buf);
/* Parse remaining parameters, reject extra parameters */
@@ -3631,7 +3786,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
}
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, 0200, NULL,
peci_sysfs_delete_device);
-@@ -1039,10 +1144,11 @@ static struct attribute *peci_adapter_attrs[] = {
+@@ -1039,10 +1143,11 @@ static struct attribute *peci_adapter_attrs[] = {
};
ATTRIBUTE_GROUPS(peci_adapter);
@@ -3644,7 +3799,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/**
* peci_verify_adapter - return parameter as peci_adapter, or NULL
-@@ -1063,32 +1169,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
+@@ -1063,32 +1168,26 @@ static struct peci_client *peci_of_register_device(struct peci_adapter *adapter,
struct device_node *node)
{
struct peci_board_info info = {};
@@ -3689,7 +3844,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
}
static void peci_of_register_devices(struct peci_adapter *adapter)
-@@ -1119,7 +1219,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter)
+@@ -1119,7 +1218,7 @@ static void peci_of_register_devices(struct peci_adapter *adapter)
of_node_put(bus);
}
@@ -3698,7 +3853,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
static void peci_of_register_devices(struct peci_adapter *adapter) { }
#endif /* CONFIG_OF */
-@@ -1163,9 +1263,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
+@@ -1163,9 +1262,7 @@ static struct peci_adapter *peci_of_find_adapter(struct device_node *node)
return adapter;
}
@@ -3709,7 +3864,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
{
struct of_reconfig_data *rd = arg;
struct peci_adapter *adapter;
-@@ -1216,7 +1314,7 @@ static int peci_of_notify(struct notifier_block *nb,
+@@ -1216,7 +1313,7 @@ static int peci_of_notify(struct notifier_block *nb,
static struct notifier_block peci_of_notifier = {
.notifier_call = peci_of_notify,
};
@@ -3718,7 +3873,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
extern struct notifier_block peci_of_notifier;
#endif /* CONFIG_OF_DYNAMIC */
-@@ -1240,7 +1338,7 @@ extern struct notifier_block peci_of_notifier;
+@@ -1240,7 +1337,7 @@ extern struct notifier_block peci_of_notifier;
*
* Return: the peci_adapter structure on success, else NULL.
*/
@@ -3727,7 +3882,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
{
struct peci_adapter *adapter;
-@@ -1263,7 +1361,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter);
+@@ -1263,7 +1360,7 @@ EXPORT_SYMBOL_GPL(peci_alloc_adapter);
static int peci_register_adapter(struct peci_adapter *adapter)
{
@@ -3736,7 +3891,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/* Can't register until after driver model init */
if (WARN_ON(!is_registered))
-@@ -1275,27 +1373,17 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+@@ -1275,27 +1372,17 @@ static int peci_register_adapter(struct peci_adapter *adapter)
if (WARN(!adapter->xfer, "peci adapter has no xfer function\n"))
goto err_free_idr;
@@ -3769,7 +3924,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
}
dev_dbg(&adapter->dev, "adapter [%s] registered\n", adapter->name);
-@@ -1309,13 +1397,11 @@ static int peci_register_adapter(struct peci_adapter *adapter)
+@@ -1309,13 +1396,11 @@ static int peci_register_adapter(struct peci_adapter *adapter)
return 0;
@@ -3784,7 +3939,24 @@ index 6f241469ec7e..d1f0df8b139a 100644
}
static int peci_add_numbered_adapter(struct peci_adapter *adapter)
-@@ -1411,7 +1497,7 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1354,12 +1439,10 @@ int peci_add_adapter(struct peci_adapter *adapter)
+ struct device *dev = &adapter->dev;
+ int id;
+
+- if (dev->of_node) {
+- id = of_alias_get_id(dev->of_node, "peci");
+- if (id >= 0) {
+- adapter->nr = id;
+- return peci_add_numbered_adapter(adapter);
+- }
++ id = of_alias_get_id(dev->of_node, "peci");
++ if (id >= 0) {
++ adapter->nr = id;
++ return peci_add_numbered_adapter(adapter);
+ }
+
+ mutex_lock(&core_lock);
+@@ -1411,7 +1494,7 @@ void peci_del_adapter(struct peci_adapter *adapter)
}
mutex_unlock(&adapter->userspace_clients_lock);
@@ -3793,7 +3965,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
* Detach any active clients. This can't fail, thus we do not
* check the returned value.
*/
-@@ -1420,13 +1506,8 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1420,13 +1503,8 @@ void peci_del_adapter(struct peci_adapter *adapter)
/* device name is gone after device_unregister */
dev_dbg(&adapter->dev, "adapter [%s] unregistered\n", adapter->name);
@@ -3807,7 +3979,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
device_unregister(&adapter->dev);
/* free bus id */
-@@ -1436,6 +1517,18 @@ void peci_del_adapter(struct peci_adapter *adapter)
+@@ -1436,6 +1514,18 @@ void peci_del_adapter(struct peci_adapter *adapter)
}
EXPORT_SYMBOL_GPL(peci_del_adapter);
@@ -3826,7 +3998,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/**
* peci_register_driver - register a PECI driver
* @owner: owner module of the driver being registered
-@@ -1446,7 +1539,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter);
+@@ -1446,7 +1536,7 @@ EXPORT_SYMBOL_GPL(peci_del_adapter);
*/
int peci_register_driver(struct module *owner, struct peci_driver *driver)
{
@@ -3835,7 +4007,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
/* Can't register until after driver model init */
if (WARN_ON(!is_registered))
-@@ -1456,13 +1549,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver)
+@@ -1456,13 +1546,13 @@ int peci_register_driver(struct module *owner, struct peci_driver *driver)
driver->driver.owner = owner;
driver->driver.bus = &peci_bus_type;
@@ -3853,7 +4025,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
pr_debug("driver [%s] registered\n", driver->driver.name);
-@@ -1492,13 +1585,6 @@ static int __init peci_init(void)
+@@ -1492,13 +1582,6 @@ static int __init peci_init(void)
return ret;
}
@@ -3867,7 +4039,7 @@ index 6f241469ec7e..d1f0df8b139a 100644
crc8_populate_msb(peci_crc8_table, PECI_CRC8_POLYNOMIAL);
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
-@@ -1514,11 +1600,10 @@ static void __exit peci_exit(void)
+@@ -1514,11 +1597,10 @@ static void __exit peci_exit(void)
if (IS_ENABLED(CONFIG_OF_DYNAMIC))
WARN_ON(of_reconfig_notifier_unregister(&peci_of_notifier));
@@ -4649,7 +4821,7 @@ index f632365b1416..000000000000
-MODULE_DESCRIPTION("NPCM Platform Environment Control Interface (PECI) driver");
-MODULE_LICENSE("GPL v2");
diff --git a/include/linux/mfd/intel-peci-client.h b/include/linux/mfd/intel-peci-client.h
-index 8f6d823a59cd..7b62a02e46ee 100644
+index 8f6d823a59cd..9854303bbc26 100644
--- a/include/linux/mfd/intel-peci-client.h
+++ b/include/linux/mfd/intel-peci-client.h
@@ -1,5 +1,5 @@
@@ -4674,22 +4846,22 @@ index 8f6d823a59cd..7b62a02e46ee 100644
-#define INTEL_FAM6_SKYLAKE_X 0x55
+#define INTEL_FAM6_HASWELL_X 0x3F
+#define INTEL_FAM6_BROADWELL_X 0x4F
-+#define INTEL_FAM6_BROADWELL_XEON_D 0x56
+#define INTEL_FAM6_SKYLAKE_X 0x55
++#define INTEL_FAM6_SKYLAKE_XD 0x56
#endif
#define CORE_MAX_ON_HSX 18 /* Max number of cores on Haswell */
-@@ -27,6 +28,10 @@
- #define CHAN_RANK_MAX_ON_BDX 4 /* Max number of channel ranks on Broadwell */
- #define DIMM_IDX_MAX_ON_BDX 3 /* Max DIMM index per channel on Broadwell */
-
-+#define CORE_MAX_ON_XD 16 /* Max number of cores on Xeon D */
-+#define CHAN_RANK_MAX_ON_XD 2 /* Max number of channel ranks on Xeon D */
-+#define DIMM_IDX_MAX_ON_XD 2 /* Max DIMM index per channel on Xeon D */
-+
- #define CORE_MAX_ON_SKX 28 /* Max number of cores on Skylake */
+@@ -31,6 +32,10 @@
#define CHAN_RANK_MAX_ON_SKX 6 /* Max number of channel ranks on Skylake */
#define DIMM_IDX_MAX_ON_SKX 2 /* Max DIMM index per channel on Skylake */
+
++#define CORE_MAX_ON_SKXD 16 /* Max number of cores on Skylake D */
++#define CHAN_RANK_MAX_ON_SKXD 2 /* Max number of channel ranks on Skylake D */
++#define DIMM_IDX_MAX_ON_SKXD 2 /* Max DIMM index per channel on Skylake D */
++
+ #define CORE_NUMS_MAX CORE_MAX_ON_SKX
+ #define CHAN_RANK_MAX CHAN_RANK_MAX_ON_HSX
+ #define DIMM_IDX_MAX DIMM_IDX_MAX_ON_HSX
@@ -58,7 +63,6 @@ struct cpu_gen_info {
/**
* struct peci_client_manager - PECI client manager information
@@ -4706,7 +4878,7 @@ index 8f6d823a59cd..7b62a02e46ee 100644
char name[PECI_NAME_SIZE];
const struct cpu_gen_info *gen_info;
};
-@@ -93,18 +96,23 @@ peci_client_read_package_config(struct peci_client_manager *priv,
+@@ -93,18 +96,22 @@ peci_client_read_package_config(struct peci_client_manager *priv,
u8 index, u16 param, u8 *data)
{
struct peci_rd_pkg_cfg_msg msg;
@@ -4722,12 +4894,11 @@ index 8f6d823a59cd..7b62a02e46ee 100644
- if (!rc)
- memcpy(data, msg.pkg_config, 4);
+ ret = peci_command(priv->client->adapter, PECI_CMD_RD_PKG_CFG, &msg);
++ if (msg.cc != PECI_DEV_CC_SUCCESS)
++ ret = -EAGAIN;
+ if (ret)
+ return ret;
+
-+ if (msg.cc != PECI_DEV_CC_SUCCESS)
-+ return -EAGAIN;
-+
+ memcpy(data, msg.pkg_config, 4);
- return rc;
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
index 0e11e1c3e..53060daf7 100644
--- a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0026-Add-support-for-new-PECI-commands.patch
@@ -588,7 +588,7 @@ index 253fb42e38b7..405cd8edbcbf 100644
+ struct peci_rd_end_pt_cfg_msg)
+
+#define PECI_IOC_WR_END_PT_CFG \
-+ _IOWR(PECI_IOC_BASE, PECI_IOC_WR_END_PT_CFG, \
++ _IOWR(PECI_IOC_BASE, PECI_CMD_WR_END_PT_CFG, \
+ struct peci_wr_end_pt_cfg_msg)
+
+#define PECI_IOC_CRASHDUMP_DISC \
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch
new file mode 100644
index 000000000..dc38c81f3
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0069-i2c-aspeed-add-SLAVE_ADDR_RECEIVED_PENDING-interrupt.patch
@@ -0,0 +1,50 @@
+From 085bde1e91d85435c44a752bd59d38cf31465518 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 11 Jul 2019 14:04:39 -0700
+Subject: [PATCH] i2c: aspeed: add SLAVE_ADDR_RECEIVED_PENDING interrupt
+ handling
+
+If a peer master sends messages too quickly before it processes
+previous slave DMA data handling, this indicator will be set. It's
+just a indicator and driver can't recover this case so just ignore
+it.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/i2c/busses/i2c-aspeed.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c
+index d41f377de9dc..46de9a01a0eb 100644
+--- a/drivers/i2c/busses/i2c-aspeed.c
++++ b/drivers/i2c/busses/i2c-aspeed.c
+@@ -86,6 +86,7 @@
+ * These share bit definitions, so use the same values for the enable &
+ * status bits.
+ */
++#define ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING BIT(30)
+ #define ASPEED_I2CD_INTR_SLAVE_INACTIVE_TIMEOUT BIT(15)
+ #define ASPEED_I2CD_INTR_SDA_DL_TIMEOUT BIT(14)
+ #define ASPEED_I2CD_INTR_BUS_RECOVER_DONE BIT(13)
+@@ -353,6 +354,18 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
+ dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
+ irq_status, command);
+
++ /*
++ * If a peer master sends messages too quickly before it processes
++ * previous slave DMA data handling, this indicator will be set. It's
++ * just a indicator and driver can't recover this case so just ignore
++ * it.
++ */
++ if (unlikely(irq_status &
++ ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING)) {
++ dev_dbg(bus->dev, "A slave addr match interrupt is pending.\n");
++ irq_handled |= ASPEED_I2CD_INTR_SLAVE_ADDR_RECEIVED_PENDING;
++ }
++
+ /* Slave was sent something. */
+ if (irq_status & ASPEED_I2CD_INTR_RX_DONE) {
+ if (bus->dma_buf &&
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch
new file mode 100644
index 000000000..4af5be95d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0070-gpio-aspeed-temporary-fix-for-gpiochip-range-setting.patch
@@ -0,0 +1,44 @@
+From 9195eef3fec7022ca52ac9791c19de2362ed042e Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Fri, 19 Jul 2019 12:54:38 -0700
+Subject: [PATCH] gpio: aspeed: temporary fix for gpiochip range setting
+
+Since we are still using fixed indices for gpio line numbers for sysfs
+interface, this commit set the gpiochip range as fixed temporariliy
+til we replace all index based gpio uses with name based uses.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/gpio/gpio-aspeed.c | 2 +-
+ drivers/gpio/sgpio-aspeed.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
+index e426452a28f7..d4aaf7fa8e4b 100644
+--- a/drivers/gpio/gpio-aspeed.c
++++ b/drivers/gpio/gpio-aspeed.c
+@@ -1189,7 +1189,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
+ gpio->chip.set = aspeed_gpio_set;
+ gpio->chip.set_config = aspeed_gpio_set_config;
+ gpio->chip.label = dev_name(&pdev->dev);
+- gpio->chip.base = -1;
++ gpio->chip.base = 0;
+ gpio->chip.irq.need_valid_mask = true;
+
+ /* Allocate a cache of the output registers */
+diff --git a/drivers/gpio/sgpio-aspeed.c b/drivers/gpio/sgpio-aspeed.c
+index 6fb402a3f74d..2f4c0aab0bf2 100644
+--- a/drivers/gpio/sgpio-aspeed.c
++++ b/drivers/gpio/sgpio-aspeed.c
+@@ -675,7 +675,7 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
+ gpio->chip.set = aspeed_sgpio_set;
+ gpio->chip.set_config = aspeed_sgpio_set_config;
+ gpio->chip.label = dev_name(&pdev->dev);
+- gpio->chip.base = -1;
++ gpio->chip.base = gpio->config->nr_pgpios;
+ gpio->chip.irq.need_valid_mask = true;
+
+ /* Allocate a cache of the output registers */
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch
new file mode 100644
index 000000000..e32ec54ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0071-peci-add-a-temporary-workaround.patch
@@ -0,0 +1,101 @@
+From 3394fabbd17ad7263feeb0f4ae593056237f0647 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Tue, 30 Jul 2019 13:01:58 -0700
+Subject: [PATCH] peci: add a temporary workaround
+
+To cover a PECI issue, this commit makes PECI driver block all PECI
+commands when PLTRST_N signal is 0.
+
+Also, it adds 'use_wa' module parameter for platforms that don't have
+the PLTRST_N gpio input so that the WA can be disabled through the
+module parameter.
+
+This is a temporary workaround.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/peci/busses/peci-aspeed.c | 11 +++++++++++
+ drivers/peci/peci-core.c | 11 +++++++++++
+ include/linux/peci.h | 1 +
+ 3 files changed, 23 insertions(+)
+
+diff --git a/drivers/peci/busses/peci-aspeed.c b/drivers/peci/busses/peci-aspeed.c
+index 8a0dd40730cc..76394ab32854 100644
+--- a/drivers/peci/busses/peci-aspeed.c
++++ b/drivers/peci/busses/peci-aspeed.c
+@@ -10,6 +10,7 @@
+ #include <linux/jiffies.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
++#include <linux/of_gpio.h>
+ #include <linux/peci.h>
+ #include <linux/platform_device.h>
+ #include <linux/reset.h>
+@@ -445,6 +446,16 @@ static int aspeed_peci_probe(struct platform_device *pdev)
+ if (ret)
+ goto err_put_adapter_dev;
+
++ priv->adapter->pltrst_pin = of_get_gpio(pdev->dev.of_node, 0);
++ if (gpio_is_valid(priv->adapter->pltrst_pin)) {
++ ret = devm_gpio_request(&pdev->dev, priv->adapter->pltrst_pin,
++ "peci-aspeed");
++ if (ret < 0) {
++ priv->adapter->pltrst_pin = -1;
++ dev_err(&pdev->dev, "error requesting pltrst gpio\n");
++ }
++ }
++
+ ret = peci_add_adapter(priv->adapter);
+ if (ret)
+ goto err_put_adapter_dev;
+diff --git a/drivers/peci/peci-core.c b/drivers/peci/peci-core.c
+index b99ba788a032..2e3b9a0c83e9 100644
+--- a/drivers/peci/peci-core.c
++++ b/drivers/peci/peci-core.c
+@@ -5,6 +5,7 @@
+ #include <linux/crc8.h>
+ #include <linux/delay.h>
+ #include <linux/mm.h>
++#include <linux/gpio.h>
+ #include <linux/module.h>
+ #include <linux/of_device.h>
+ #include <linux/peci.h>
+@@ -190,6 +191,11 @@ static int peci_aw_fcs(struct peci_xfer_msg *msg, int len, u8 *aw_fcs)
+ return 0;
+ }
+
++/* Temporary WA */
++static bool use_wa __read_mostly = true;
++module_param_named(use_wa, use_wa, bool, 0644);
++MODULE_PARM_DESC(use_wa, "flag for enabling of WA");
++
+ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+ bool do_retry, bool has_aw_fcs)
+ {
+@@ -197,6 +203,11 @@ static int __peci_xfer(struct peci_adapter *adapter, struct peci_xfer_msg *msg,
+ u8 aw_fcs;
+ int ret;
+
++ /* Temporary WA */
++ if (use_wa && gpio_is_valid(adapter->pltrst_pin) &&
++ gpio_get_value(adapter->pltrst_pin) == 0)
++ return -EAGAIN;
++
+ /*
+ * In case if adapter uses DMA, check at here whether tx and rx buffers
+ * are DMA capable or not.
+diff --git a/include/linux/peci.h b/include/linux/peci.h
+index 6fc424dc2a73..e589cb258a2a 100644
+--- a/include/linux/peci.h
++++ b/include/linux/peci.h
+@@ -44,6 +44,7 @@ struct peci_adapter {
+ struct peci_xfer_msg *msg);
+ u32 cmd_mask;
+ bool use_dma;
++ int pltrst_pin;
+ };
+
+ static inline struct peci_adapter *to_peci_adapter(void *d)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch
new file mode 100644
index 000000000..40a9272e0
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0072-pmbus-add-fault-and-beep-attributes.patch
@@ -0,0 +1,88 @@
+From e360a6c2a3f15bfc8900c7262c56f9bcd5e0f16e Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 8 Aug 2019 10:38:00 -0700
+Subject: [PATCH] pmbus: add 'fault' and 'beep' attributes
+
+This commit adds two more attirbutes to reflect MFR_SPECIFIC bit in
+the STATUS_WORD and 'Unit Off For Insufficient Input Voltage' bit in
+the STATUS_INPUT into 'fault' and 'beep' attributes respectively.
+
+The attributes will be enumerated as 'inX_fault' and 'inX_beep' in
+a 'vin' group.
+
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ drivers/hwmon/pmbus/pmbus.h | 1 +
+ drivers/hwmon/pmbus/pmbus_core.c | 30 ++++++++++++++++++++++++++++++
+ 2 files changed, 31 insertions(+)
+
+diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
+index d198af3a92b6..09e6fe01c304 100644
+--- a/drivers/hwmon/pmbus/pmbus.h
++++ b/drivers/hwmon/pmbus/pmbus.h
+@@ -303,6 +303,7 @@ enum pmbus_fan_mode { percent = 0, rpm };
+ #define PB_PIN_OP_WARNING BIT(0)
+ #define PB_IIN_OC_WARNING BIT(1)
+ #define PB_IIN_OC_FAULT BIT(2)
++#define PB_UNIT_OFF_FOR_INSUF_VIN BIT(3)
+
+ /*
+ * STATUS_TEMPERATURE
+diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
+index 898d7378f4f8..85295a45c3ba 100644
+--- a/drivers/hwmon/pmbus/pmbus_core.c
++++ b/drivers/hwmon/pmbus/pmbus_core.c
+@@ -1163,6 +1163,8 @@ struct pmbus_limit_attr {
+ struct pmbus_sensor_attr {
+ u16 reg; /* sensor register */
+ u16 gbit; /* generic status bit */
++ u16 gfbit; /* generic fault status bit */
++ u16 sbbit; /* beep status bit */
+ u8 nlimit; /* # of limit registers */
+ enum pmbus_sensor_classes class;/* sensor class */
+ const char *label; /* sensor label */
+@@ -1264,6 +1266,32 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client,
+ return ret;
+ }
+ }
++ /*
++ * Add fault attribute if there is a generic fault bit, and if
++ * the generic status register (word or byte, depending on which global
++ * bit is set) for this page is accessible.
++ */
++ if (attr->gfbit) {
++ upper = !!(attr->gfbit & 0xff00); /* need to check STATUS_WORD */
++ if ((!upper || (upper && data->has_status_word)) &&
++ pmbus_check_status_register(client, page)) {
++ ret = pmbus_add_boolean(data, name, "fault", index,
++ NULL, NULL,
++ PB_STATUS_BASE + page,
++ attr->gfbit);
++ if (ret)
++ return ret;
++ }
++ }
++ /* Add beep attribute if there is a beep status bit. */
++ if (attr->sbbit) {
++ ret = pmbus_add_boolean(data, name, "beep", index,
++ NULL, NULL,
++ attr->sbase + page,
++ attr->sbbit);
++ if (ret)
++ return ret;
++ }
+ return 0;
+ }
+
+@@ -1435,6 +1463,8 @@ static const struct pmbus_sensor_attr voltage_attributes[] = {
+ .gbit = PB_STATUS_VIN_UV,
+ .limit = vin_limit_attrs,
+ .nlimit = ARRAY_SIZE(vin_limit_attrs),
++ .gfbit = PB_STATUS_WORD_MFR,
++ .sbbit = PB_UNIT_OFF_FOR_INSUF_VIN,
+ }, {
+ .reg = PMBUS_VIRT_READ_VMON,
+ .class = PSC_VOLTAGE_IN,
+--
+2.7.4
+