Commit 618337b8 authored by Marc Jones's avatar Marc Jones Committed by chrome-bot
Browse files

amd/kern: Add GPIO driver



Add a driver where the functions are modelled after the Lynxpoint-LP.
The Kern FCH  in Stoney Ridge uses GPIO and IOMux registers at fixed
offsets from a memory-mapped location.

BRANCH=none
BUG=b:62457067
TEST=Builds clean.

Change-Id: If7d9b66762334da2ea428f6e77fa55625817eeda
Signed-off-by: default avatarMarshall Dawson <marshalldawson3rd@gmail.com>
Signed-off-by: default avatarMarc Jones <marc.jones@scarletltd.com>
Reviewed-on: https://chromium-review.googlesource.com/474052


Commit-Ready: Martin Roth <martinroth@chromium.org>
Tested-by: default avatarMartin Roth <martinroth@chromium.org>
Reviewed-by: default avatarMartin Roth <martinroth@chromium.org>
Reviewed-by: default avatarStefan Reinauer <reinauer@google.com>
parent fde21647
......@@ -95,3 +95,7 @@ config DRIVER_GPIO_TEGRA
config DRIVER_GPIO_APOLLOLAKE
bool "Intel Apollolake GPIO driver"
default n
config DRIVER_GPIO_KERN
bool "AMD Kern FCH GPIO driver"
default n
......@@ -32,3 +32,4 @@ depthcharge-$(CONFIG_DRIVER_GPIO_RK3399) += rk3399.c
depthcharge-$(CONFIG_DRIVER_GPIO_SKYLAKE) += skylake.c
depthcharge-$(CONFIG_DRIVER_GPIO_TEGRA) += tegra.c
depthcharge-$(CONFIG_DRIVER_GPIO_APOLLOLAKE) += apollolake.c
depthcharge-$(CONFIG_DRIVER_GPIO_KERN) += kern.c
/*
* Copyright (C) 2015 Google Inc.
* Copyright (C) 2017 Advanced Micro Devices, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <assert.h>
#include <libpayload.h>
#include <stdint.h>
#include "base/container_of.h"
#include "drivers/gpio/gpio.h"
#include "drivers/gpio/kern.h"
#define KERN_PM_MMIO 0xfed80000
#define FCH_GPIO_REG(num) ((num) * 4)
#define FCH_GPIO_OUTPUT_EN 23
#define FCH_GPIO_OUTPUT_VAL 22
#define FCH_GPIO_INPUT_VAL 28
/* Functions for manipulating GPIO regs. */
static uintptr_t fch_gpiobase(void)
{
return KERN_PM_MMIO + 0x1500;
}
static uintptr_t fch_iomuxbase(void)
{
return KERN_PM_MMIO + 0xd00;
}
/* Careful! MUX setting for GPIOn is not consistent for all pins. See BKDG. */
static int fch_iomux_set(unsigned num, int val)
{
uint8_t *addr = phys_to_virt(fch_iomuxbase + num);
*addr = 0x3 & (uint8_t)val;
return 0;
}
static int fch_gpio_set(unsigned num, int bit, int val)
{
uint32_t *addr = phys_to_virt(fch_gpiobase + FCH_GPIO_REG(num));
uint32_t conf = *addr;
if (val)
conf |= (1 << bit);
else
conf &= ~(1 << bit);
*addr = conf;
return 0;
}
static int fch_gpio_get(unsigned num, int bit)
{
uint32_t *addr = phys_to_virt(fch_gpiobase + FCH_GPIO_REG(num));
uint32_t conf = *addr;
return !!(conf & (1 << bit));
}
/* Interface functions for manipulating a GPIO. */
static int kern_fch_gpio_get_value(GpioOps *me)
{
assert(me);
KernGpio *gpio = container_of(me, KernGpio, ops);
if (!gpio->dir_set) {
/* Unnecessary but disable output so we can trust input */
if (fch_gpio_set(gpio->num, FCH_GPIO_OUTPUT_EN, 0) < 0)
return -1;
gpio->dir_set = 1;
}
return fch_gpio_get(gpio->num, FCH_GPIO_INPUT_VAL);
}
static int kern_fch_gpio_set_value(GpioOps *me, unsigned value)
{
assert(me);
KernGpio *gpio = container_of(me, KernGpio, ops);
if (!gpio->dir_set) {
if (fch_gpio_set(gpio->num, FCH_GPIO_OUTPUT_EN, 1) < 0)
return -1;
gpio->dir_set = 1;
}
return fch_gpio_set(gpio->num, FCH_GPIO_OUTPUT_VAL, value);
}
static int kern_fch_gpio_use(KernGpio *me, unsigned use)
{
assert(me);
return fch_iomux_set(me->num, use);
}
/* Functions to allocate and set up a GPIO structure. */
KernGpio *new_kern_fch_gpio(unsigned num)
{
KernGpio *gpio = xzalloc(sizeof(*gpio));
gpio->use = &kern_fch_gpio_use;
gpio->num = num;
return gpio;
}
KernGpio *new_kern_fch_gpio_input(unsigned num)
{
KernGpio *gpio = new_kern_fch_gpio(num);
gpio->ops.get = &kern_fch_gpio_get_value;
return gpio;
}
KernGpio *new_kern_fch_gpio_output(unsigned num)
{
KernGpio *gpio = new_kern_fch_gpio(num);
gpio->ops.set = &kern_fch_gpio_set_value;
return gpio;
}
/*
* Copyright 2013 Google Inc.
* Copyright (C) 2016 Advanced Micro Devices, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but without any warranty; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __DRIVERS_GPIO_KERN_H__
#define __DRIVERS_GPIO_KERN_H__
#include "drivers/gpio/gpio.h"
typedef struct KernGpio
{
GpioOps ops;
int (*use)(struct KernGpio *, unsigned use);
int num;
int dir_set;
} KernGpio;
KernGpio *new_kern_gpio(unsigned num);
KernGpio *new_kern_fch_gpio_output(unsigned num);
KernGpio *new_kern_fch_gpio_input(unsigned num);
#endif /* __DRIVERS_GPIO_KERN_H__ */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment