Commit 094a935d authored by danh-arm's avatar danh-arm
Browse files

Merge pull request #518 from hzhuang1/pl061_gpio_v5

Pl061 gpio v5
parents 6f8016b8 7dc4b227
......@@ -476,6 +476,18 @@ memory layout implies some image overlaying like in ARM standard platforms.
Defines the maximum address that the TSP's progbits sections can occupy.
If the platform port uses the PL061 GPIO driver, the following constant may
optionally be defined:
* **PLAT_PL061_MAX_GPIOS**
Maximum number of GPIOs required by the platform. This allows control how
much memory is allocated for PL061 GPIO controllers. The default value is
32.
[For example, define the build flag in platform.mk]:
PLAT_PL061_MAX_GPIOS := 160
$(eval $(call add_define,PLAT_PL061_MAX_GPIOS))
### File : plat_macros.S [mandatory]
Each platform must ensure a file of this name is in the system include path with
......
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* ARM PL061 GPIO Driver.
* Reference to ARM DDI 0190B document.
*
*/
#include <assert.h>
#include <cassert.h>
#include <debug.h>
#include <errno.h>
#include <gpio.h>
#include <mmio.h>
#include <pl061_gpio.h>
#if !PLAT_PL061_MAX_GPIOS
# define PLAT_PL061_MAX_GPIOS 32
#endif /* PLAT_PL061_MAX_GPIOS */
CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios);
#define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \
(GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061)
#define PL061_GPIO_DIR 0x400
#define GPIOS_PER_PL061 8
#define BIT(nr) (1UL << (nr))
static int pl061_get_direction(int gpio);
static void pl061_set_direction(int gpio, int direction);
static int pl061_get_value(int gpio);
static void pl061_set_value(int gpio, int value);
static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES];
static const gpio_ops_t pl061_gpio_ops = {
.get_direction = pl061_get_direction,
.set_direction = pl061_set_direction,
.get_value = pl061_get_value,
.set_value = pl061_set_value,
};
static int pl061_get_direction(int gpio)
{
uintptr_t base_addr;
unsigned int data, offset;
assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
offset = gpio % GPIOS_PER_PL061;
data = mmio_read_8(base_addr + PL061_GPIO_DIR);
if (data & BIT(offset))
return GPIO_DIR_OUT;
return GPIO_DIR_IN;
}
static void pl061_set_direction(int gpio, int direction)
{
uintptr_t base_addr;
unsigned int data, offset;
assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
offset = gpio % GPIOS_PER_PL061;
if (direction == GPIO_DIR_OUT) {
data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset);
mmio_write_8(base_addr + PL061_GPIO_DIR, data);
} else {
data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset);
mmio_write_8(base_addr + PL061_GPIO_DIR, data);
}
}
/*
* The offset of GPIODATA register is 0.
* The values read from GPIODATA are determined for each bit, by the mask bit
* derived from the address used to access the data register, PADDR[9:2].
* Bits that are 1 in the address mask cause the corresponding bits in GPIODATA
* to be read, and bits that are 0 in the address mask cause the corresponding
* bits in GPIODATA to be read as 0, regardless of their value.
*/
static int pl061_get_value(int gpio)
{
uintptr_t base_addr;
unsigned int offset;
assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
offset = gpio % GPIOS_PER_PL061;
if (mmio_read_8(base_addr + BIT(offset + 2)))
return GPIO_LEVEL_HIGH;
return GPIO_LEVEL_LOW;
}
/*
* In order to write GPIODATA, the corresponding bits in the mask, resulting
* from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values
* remain unchanged by the write.
*/
static void pl061_set_value(int gpio, int value)
{
uintptr_t base_addr;
int offset;
assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS));
base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061];
offset = gpio % GPIOS_PER_PL061;
if (value == GPIO_LEVEL_HIGH)
mmio_write_8(base_addr + BIT(offset + 2), BIT(offset));
else
mmio_write_8(base_addr + BIT(offset + 2), 0);
}
/*
* Register the PL061 GPIO controller with a base address and the offset
* of start pin in this GPIO controller.
* This function is called after pl061_gpio_ops_init().
*/
void pl061_gpio_register(uintptr_t base_addr, int gpio_dev)
{
assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES));
pl061_reg_base[gpio_dev] = base_addr;
}
/*
* Initialize PL061 GPIO controller with the total GPIO numbers in SoC.
*/
void pl061_gpio_init(void)
{
gpio_init(&pl061_gpio_ops);
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* GPIO -- General Purpose Input/Output
*
* Defines a simple and generic interface to access GPIO device.
*
*/
#include <assert.h>
#include <errno.h>
#include <gpio.h>
/*
* The gpio implementation
*/
static const gpio_ops_t *ops;
int gpio_get_direction(int gpio)
{
assert(ops);
assert(ops->get_direction != 0);
assert(gpio >= 0);
return ops->get_direction(gpio);
}
void gpio_set_direction(int gpio, int direction)
{
assert(ops);
assert(ops->set_direction != 0);
assert((direction == GPIO_DIR_OUT) || (direction == GPIO_DIR_IN));
assert(gpio >= 0);
ops->set_direction(gpio, direction);
}
int gpio_get_value(int gpio)
{
assert(ops);
assert(ops->get_value != 0);
assert(gpio >= 0);
return ops->get_value(gpio);
}
void gpio_set_value(int gpio, int value)
{
assert(ops);
assert(ops->set_value != 0);
assert((value == GPIO_LEVEL_LOW) || (value == GPIO_LEVEL_HIGH));
assert(gpio >= 0);
ops->set_value(gpio, value);
}
/*
* Initialize the gpio. The fields in the provided gpio
* ops pointer must be valid.
*/
void gpio_init(const gpio_ops_t *ops_ptr)
{
assert(ops_ptr != 0 &&
(ops_ptr->get_direction != 0) &&
(ops_ptr->set_direction != 0) &&
(ops_ptr->get_value != 0) &&
(ops_ptr->set_value != 0));
ops = ops_ptr;
}
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __PL061_GPIO_H__
#define __PL061_GPIO_H__
#include <gpio.h>
void pl061_gpio_register(uintptr_t base_addr, int gpio_dev);
void pl061_gpio_init(void);
#endif /* __PL061_GPIO_H__ */
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of ARM nor the names of its contributors may be used
* to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __GPIO_H__
#define __GPIO_H__
#define GPIO_DIR_OUT 0
#define GPIO_DIR_IN 1
#define GPIO_LEVEL_LOW 0
#define GPIO_LEVEL_HIGH 1
typedef struct gpio_ops {
int (*get_direction)(int gpio);
void (*set_direction)(int gpio, int direction);
int (*get_value)(int gpio);
void (*set_value)(int gpio, int value);
} gpio_ops_t;
int gpio_get_direction(int gpio);
void gpio_set_direction(int gpio, int direction);
int gpio_get_value(int gpio);
void gpio_set_value(int gpio, int value);
void gpio_init(const gpio_ops_t *ops);
#endif /* __GPIO_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