[Uboot] uboot process series :
[Project X] tiny210 (s5pv210) power-on START process (BL0-BL2)
[Project X] tiny210 (s5pv210) load code from storage device to DDR
[Uboot] (chapter I) uboot process--Overview
[Uboot] (chapter II) uboot process--UBOOT-SPL compilation process
[Uboot] (chapter III) uboot process--UBOOT-SPL code flow
[Uboot] (fourth chapter) Uboot process--uboot compilation process
[Uboot] (fifth) Uboot process--uboot START process
[Uboot] (Foreign article) Global_data Introduction
[Uboot] (foreign article) uboot Relocation Introduction
[Uboot] (external) Uboot Drive model
It is recommended to look at "[Uboot] (foreign) Uboot drive Model"
=============================================================================================================
Dm-gpio One, Dm-gpio architecture
It is recommended to refer to "[Uboot] (foreign) Uboot drive model" to understand the driving model under Uboot.
1. Dm-gpio Architecture Diagram
As follows:
2. Description of
Gpio core
Also implemented in Gpio Uclass,
The main is to provide an interface for the upper layer to obtain the Gpio property from DTS to obtain the corresponding Udevice device from the device chain list of Gpio Uclass and use its operation set
Gpio Uclass links All Gpio udevice devices belonging to the Uclass provide a unified set of operation interfaces for the driver of Gpio Udevice
Bank and Gpio on some platforms, some of the gpio using the same set of registers constitute a bank, for example, Samsung's s5pv210 of course, not all platforms have a bank concept, such as Qualcomm, high-pass GPIO has its own independent registers, therefore, You can think of Qualcomm as just a bank.
Gpio udevice A bank corresponds to a gpio udevice, using the offset in the bank to represent the specific Gpio number Gpio Udevice's driver will operate on the corresponding bit on the corresponding register according to the bank and offset.
3. Introduction of principle
Here is a brief introduction to the DM under the working principle of the Gpio a bank corresponding to a udevice,udevice in the private data stored in the bank information, such as the corresponding register address and so on the upper layer with the GPIO_DESC descriptor describes a gpio, This includes the Udevice to which the gpio belongs, the offsets within the bank, and the flag bits. The upper layer obtains the GPIO_DESC descriptor corresponding to the Gpio attribute from DTSi by calling the Gpio core interface with the GPIO_DESC descriptor as the parameter of the operation interface that invokes the Gpio core from the Gpio_ The DESC descriptor extracts the Udevice, and calls the corresponding set of operations in its driver, takes the offset in the bank as its parameter (so that driver can determine which gpio it is) driver extract the bank information from the Udevice private data, and to do the corresponding operation
second, the use of Dm-gpio example
Here's a simple example of the use of Gpio with the tiny210 led_1 flashing.
Although the Uboot has implemented the LED Uclass, but we do not use this uclass here, just simple implementation through the Dm-gpio to control an LED.
0, the hardware simple description (specific to refer to schematic bar)
The address space of the s5pv210 Gpio
Refer to "s5pv210_um_rev1.1" 2.1.2 Special FUNCTION REGISTER MAP,
S5PV210 Gpio has an address space of 0xe020_0000 beginning with the area of 1000B
On the tiny210, there are four LEDs, low level is light, high level is off Gpj2_0, Led_1 gpj2_1, Led_2 gpj2_2, Led_3 gpj2_3
GPJ2 this bank register.
Corresponding control register 0xe020_0280
Corresponding data register 0xe020_0284 1, dtsi definition
This only describes the node of the Gpio reference, does not describe the node of the Gpio controller, the node of the Gpio controller is described in the following driver
Arch/arm/dts/s5pv210-tiny210.dts
led_test {
compatible = "Dm-gpio,test";
Led1-gpio = <&gpj2 0 0>; The property "Led1-gpio", which indicates that the No. 0 gpio,0 of the Gpj2 bank is a value flag
Led2-gpio = <&gpj2 1 0>; The 1th gpio,0 of the Gpj2 bank is a value flag
Led3-gpio = <&gpj2 2 0>; The 2nd gpio,0 of the Gpj2 bank is a value flag
Led4-gpio = <&gpj2 3 0>; The 3rd gpio,0 of the Gpj2 bank is a value flag
};
Note that the <&gpj2 0 0> here depends on how driver is transforming this property. Not all platforms are the same. 2. Obtain a gpio from the node in the drive
We are in the board_late_init to achieve the Gpio flicker function
Board/samsung/tiny210/board.c
int board_late_init(void)
{
struct gpio_desc led1_gpio;
Int node;
node = fdt_node_offset_by_compatible(gd->fdt_blob, 0, "dm-gpio,test");
//Note that we do not use the driver of DM model to match the nodes with compatible = DM GPIO, test, so we directly obtain the nodes with compatible = DM GPIO, test and store them in the node
if (node < 0)
{
printf("===========================Don't find dm-gpio,test node\n");
Return -1;
}
gpio_request_by_name_nodev(gd->fdt_blob, node, "led1-gpio", 0, &led1_gpio, GPIOD_IS_OUT);
//Call GPIO ﹐ request ﹐ by ﹐ name ﹐ nodev to get the "LED1 GPIO" attribute in the node node, and convert it to GPIO ﹐ desc descriptor, marked as output
If (DM ﹣ GPIO ﹣ is ﹣ & LED1 ﹣ GPIO)) / / judge whether the corresponding GPIO ﹣ desc is available
{
printf("===========================Get led1-gpio\n");
While (1)
{
DM? GPIO? Set? Value (& LED1? GPIO, 0); / / call DM? GPIO? Set? Value to output LED1? GPIO to low level
mdelay(1000);
DM? GPIO? Set? Value (& LED1? GPIO, 1); / / call DM? GPIO? Set? Value to output LED1? GPIO to high level
mdelay(1000);
}
}
Else
{
printf("===========================Can't get led1-gpio\n");
}
3. Brief description
The Gpio required in DTSi is described in a certain format in the attribute, as follows:
Led1-gpio = <&gpj2 0 0>; Call the Gpio_request_by_name_nodev interface in the driver or another interface to obtain the GPIO_DESC descriptor of the corresponding Gpio attribute from the DTSi node dm_gpio_is_valid determine if the GPIO_DESC is available The DM operation interface of Gpio Core is called, and the purpose of controlling gpio is realized by Gpio_desc parameters.
The implementation of Dm-gpio is described in the following
third, Gpio Uclass
It is recommended to refer to "[Uboot] (foreign) Uboot drive model" to understand the driving model under Uboot.
Two parts are implemented in Gpio Uclass, Gpio uclass driver:gpio uclass driver, some operations before and after the Gpio Udevice binding to the Uclass device list, and Udevice's driver operation set specification. Gpio Core: Operating interface with GPIO for upper layer
1, macro to open
(1) CONFIG_DM
Dm-gpio is based on uboot DM implementation, about Uboot DM can refer to "[Uboot] (chapter) Uboot Drive model."
So you need to enable DM, that is, to open CONFIG_DM macros.
The following are defined in Configs/tiny210_defconfig:
Config_dm=y
(2) Open CONFIG_DM_GPIO macro
The following are defined in Configs/tiny210_defconfig:
Config_dm_gpio=y
2. Description of structural body
(1) Gpio_desc
As I said earlier, the upper layer interacts with the GPIO core through Gpio_desc.
struct Gpio_desc {
struct udevice *dev; /* device, NULL for invalid GPIO * ///Udevice device corresponding to bank
unsigned long flags;
UINT Offset; /* Gpio offset within the device *//The GPIO is offset within the bank
};
Offset corresponds to the offsets within the bank, and the specific Gpio number (for compatibility with older versions) can be obtained by Offset+bank's gpio_base.
The interface that calls Uclass can obtain the corresponding GPIO descriptor directly from DTS. This method is recommended for use with GPIO under the DM framework.
(2) Gpio_dev_priv
The Udevice under each GPIO uclass device list has a portion of the private data belonging to Uclass. Udevice->uclass_priv.
There is one such data structure that is provided to Gpio Uclass for use, allowing Gpio uclass to know the Gpio information and conditions in this udevice.
struct Gpio_dev_priv {
const char *bank_name; Udevice's name is also the bank name
unsigned gpio_count;//The number of Gpio in this bank
unsigned gpio_base;//Each bank's Gpio holds Gpio Uclass is part of a contiguous gpio space, and Gpio_base represents the bank's first gpio number.
char **name;// array, after each gpio is request, will have its own label name, stored here, can prevent the GPIO request conflict
};
(3) operating set of standard Dm-gpio
struct Dm_gpio_ops {
int (*request) (struct udevice *dev, unsigned offset, const char *label);
Int (*free) (struct udevice *dev, unsigned offset);
Int (*direction_input) (struct udevice *dev, unsigned offset);
Int (*direction_output) (struct udevice *dev, unsigned offset,
int value);
Int (*get_value) (struct udevice *dev, unsigned offset);
Int (*set_value) (struct udevice *dev, unsigned offset, int value);
Int (*get_function) (struct udevice *dev, unsigned offset);
/* See here the comments */
Int (*xlate) (struct udevice *dev, struct gpio_desc *desc,
struct Fdtdec_phandle_args *args);
};
Note that the Udevice and the Bank of the offset as a parameter, the driver can be based on Udevice to obtain the corresponding bank information and private data, and then based on the offset can be identified in the end which Gpio.
3, Gpio uclass driver
The Uclass of the Gpio module in the DM model. Define the module pre-loading and post-load operation functions and so on.
Uclass_driver (Gpio) = {
. id = Uclass_gpio,
. Name = "Gpio",
. Flags = Dm_uc_flag_seq_alias,
. Post_probe = Gpio_post_probe,
. Pre_remove = Gpio_pre_remove,
. per_device_auto_alloc_size = sizeof ( struct gpio_dev_priv),
};
(1) Gpio_post_probe
The gpio_post_probe is called after the Gpio Udevice probe, and is implemented as follows:
static int gpio_post_probe (struct udevice *dev)
{
struct Gpio_dev_priv *uc_priv = Dev_get_uclass_priv (dev); /Get the udevice of just probe to uclass using private data
Uc_priv->name = calloc (uc_priv->gpio_count, sizeof (char *)); Allocates the space
if (!uc_priv->name) Return-enomem for the Gpio label in the private data
;
Return Gpio_renumber (NULL); Reassign Gpio Space
}
4. Gpio Core
The main responsibility is to provide an interface to the upper layer via Gpio uclass
(1) Interface description
It provides both an interface compatible with the old version and an interface under the DM framework.
Interface under the DM framework
Note that external Gpio_desc are used to describe a gpio, so these interfaces are gpio_desc as parameters Gpio_request_by_name
int gpio_request_by_name (struct udevice *dev, const char *list_name, int index, struct GPIO_DESC *desc, int flags)
Use the corresponding udevice to find the Gpio attribute named List_name in its DTSi node and convert it to GPIO_DESC, and request. Gpio_request_by_name_nodev
int Gpio_request_by_name_nodev (const void *blob, int node, const char *list_name, int index, struct gpio_desc *desc, int f Lags
The Gpio attribute named List_name in the corresponding DTSi node is converted to Gpio_desc and request. Dm_gpio_request
int dm_gpio_request (struct gpio_desc *desc, const char *label)
Request Gpio_desc Description of Gpio Dm_gpio_get_value
int dm_gpio_get_value (const struct GPIO_DESC *desc)
Gets the value of the Gpio described by Gpio_desc Dm_gpio_set_value
int dm_gpio_set_value (const struct GPIO_DESC *desc, int value)
Sets the value of the Gpio described by Gpio_desc dm_gpio_set_dir_flags
int dm_gpio_set_dir_flags (struct GPIO_DESC *desc, ULONG flags)
Sets the input and output direction of the Gpio described by the GPIO_DESC, with the flag Dm_gpio_set_dir
int Dm_gpio_set_dir (struct gpio_desc *desc)
Sets the input and output direction of the Gpio described by Gpio_desc dm_gpio_is_valid
Static inline bool Dm_gpio_is_valid (const struct GPIO_DESC *desc)
Determine if GPIO_DESC is available
Old interface:
These interfaces are intended to be compatible with older versions of the interface, note, but will eventually invoke the interface under the DM framework Gpio_request
int gpio_request (unsigned gpio, const char *label)
Apply for a Gpio gpio_direction_input
int gpio_direction_input (unsigned gpio)
Set a gpio as input gpio_direction_output
int gpio_direction_output (unsigned gpio, int value)
Set a gpio as output gpio_get_value
int Gpio_get_value (unsigned gpio)
Gets the value on a gpio gpio_set_value
int Gpio_set_value (unsigned gpio, int value)
Setting the value of a Gpio
(2) Example: Dm_gpio_set_value
int dm_gpio_set_value (const struct GPIO_DESC *desc, int value)
{
int ret;
ret = check_reserved (desc, "Set_value"); To determine if the GPIO has been asked, it must be a request before it can be used
if (ret)
return ret;
if (Desc->flags & gpiod_active_low)
value =!value;
Gpio_get_ops (Desc->dev)->set_value (Desc->dev, Desc->offset, value);
First obtains the corresponding Udevice driver, namely corresponds to the bank Drvier operation concentrated Set_value method,
//Then takes the Udevice, the bank offset, the level value for the parameter to pass to the Set_value method
/ /The rest is in driver, driver need to be able to udevice and bank offset operation to the corresponding Gpio to
return 0;
}
(3) Example: Gpio_set_value
int Gpio_set_value (unsigned gpio, int value)
{
struct gpio_desc desc;
int ret;
ret = Gpio_to_device (Gpio, &desc); Convert Gpio to corresponding GPIO_DESC descriptor
//Front We also said that all banks occupy part of Uclass's gpio space and are contiguous and non-conflicting, so uclass core can convert the corresponding gpio to Gpio_ DESC Descriptor
//concretely implement yourself see Code
if (ret)
return ret;
Return Dm_gpio_set_value (&desc, value);
}
Fourth, Gpio driver
All drivers have their own way of parsing gpio_desc, here we take s5pv210 as an example:
Different driver may vary greatly. Here only as a reference.
DRIVERS/GPIOS5P_GPIO.C
0, Key notes
all banks have corresponding udevice, so the binding process requires the creation of private data about the bank in the Udevice.
s5pv210 This private data is:
struct S5p_gpio_bank {
unsigned int con;
unsigned int dat;
unsigned int pull ;
unsigned int DRV;
unsigned int pdn_con;
unsigned int pdn_pull;
unsigned char res1[8];
};
Its size is exactly the length of the address space of a bank's occupied register. And the meaning also corresponds to the register.
In addition, s5pv210 does not create a matching node for each bank (note that the node is a matching node rather than a node, that the matching node refers to the node with the compitable attribute), but rather that all the bank nodes are placed under a matching node , and driver will probe the bank node under this node when bind is the matching node. The matching node does not do the probe operation.
1, definitions in DTSi
/{
pinctrl:pinctrl@e0200000 {
compatible = "Samsung,s5pc110-pinctrl"; Only this node is matched, but during the bind process of this node, the corresponding Udevice is created for the Bank of the child node and bound to the Gpio Uclass, then probe the child node
reg = <0xe0200000 0x1000 >;
#address-cells = <1>;
#size-cells = <1>;
gpa0:gpa0 {
gpio-controller;
#gpio-cells = <2>;
};
GPA1:GPA1 {
gpio-controller;
#gpio-cells = <2>;
};
GPB:GPB {
gpio-controller;
#gpio-cells = <2>;
};
gpc0:gpc0 {
gpio-controller;
#gpio-cells = <2>;
};
The bank in the back is not written here ...
};
Note that the bank here is sequential and must be exactly the same as the bank's order on the hardware.
2. Define a driver
Specific members of the significance of reference to the [Uboot] (foreign) Uboot drive model
U_boot_driver (Gpio_exynos) = {
. Name = "Gpio_exynos",
. id = uclass_gpio,//define the ID of the uclass to which it belongs
. Of_match = Exynos_gpio_ids,
. Bind = Gpio_exynos_bind,
. Probe = Gpio_exynos_probe,
. priv_auto_alloc_size = sizeof (struct exynos_bank_info),
. Ops = &gpio_exynos_ops,
};
3. Realize Exynos_gpio_ids
static const struct UDEVICE_ID exynos_gpio_ids[] = {
{. compatible = "Samsung,s5pc100-pinctrl"},
{. Compatible = "Samsung,s5pc110-pinctrl"},
{. Compatible = "Samsung,exynos4210-pinctrl"},
{. compatible = "Samsung, Exynos4x12-pinctrl "},
{. Compatible =" Samsung,exynos5250-pinctrl "},
{. compatible =" Samsung, Exynos5420-pinctrl "},
{}
};
4. Realize Gpio_exynos_bind
The corresponding Udevice is bound to the action on the Uclass
static int gpio_exynos_bind (struct udevice *parent) {struct Exynos_gpio_platdata *plat = parent->platdata;
struct S5p_gpio_bank *bank, *base;
const void *blob = gd->fdt_blob;
int node;
/* If this was a child device, there are nothing to do here */if (plat) return 0; Only the matching node, which is the parent node of all bank nodes, will do this operation base = (struct S5p_gpio_bank *) dev_get_addr (parent);
Gets the base address for the GPIO register for (node = Fdt_first_subnode (Blob, parent->of_offset), Bank = base;
Node > 0;
node = Fdt_next_subnode (blob, node), bank++) {//Traverse all child nodes struct Exynos_gpio_platdata *plat;
struct Udevice *dev;
fdt_addr_t reg;
int ret;
if (!fdtdec_get_bool (BLOB, node, "Gpio-controller"))//Determine if there is a "Gpio-controller" attribute, that is, whether a bank continue; Plat = calloc (1, sizeof (*plat));
Allocation platform data if (!plat) Return-enomem; Plat->bank_name = Fdt_get_name (BLOB, node, NULL); Set the part of the platform dataThe value ret = device_bind (parent, parent->driver,//bound sub-device, where Udevice is created for the bank and bound to the Gpio Uclass plat
->bank_name, Plat,-1, &dev);
if (ret) return ret; Dev->of_offset = node;
Node Reg = dev_get_addr (dev) corresponding to the udevice of the device bank; if (reg! = fdt_addr_t_none) bank = (struct S5p_gpio_bank *) ((ULONG) base + reg);
All the bank's physical space is arranged in this way, and the length is the same. Plat->bank = Bank;
Set the physical address of the bank debug ("Dev at%p:%s\n", bank, Plat->bank_name);
} return 0; }
5. Realize Gpio_exynos_probe
static int gpio_exynos_probe (struct udevice *dev)
{
struct Gpio_dev_priv *uc_priv = Dev_get_uclass_priv (dev); C3/>struct exynos_bank_info *priv = dev->priv;
struct Exynos_gpio_platdata *plat = dev->platdata;
/* Only the child devices has ports *
/if (!plat)
return 0;
Only the bank node will do the probe operation, and the bank's parent node will not do probe operation
Priv->bank = plat->bank;//Set the bank's private data
Uc_priv->gpio_ Count = Gpio_per_bank; Sets the private data provided to Uclass for use gpio_dev_priv
uc_priv->bank_name = plat->bank_name;//Set up private data for uclass use GPIO_DEV_ Priv
return 0;
}
6. Implement operation set
Used to provide a udevice corresponding bank operation set for Gpio Uclass, which must be defined using Dm_gpio_ops
static const struct Dm_gpio_ops gpio_exynos_ops = {
. direction_input = Exynos_gpio_direction_input,
. Direction_output = Exynos_gpio_direction_output,
. Get_value = Exynos_gpio_get_value,
. Set_value = Exynos_gpio_set_value,
. get_function = exynos_gpio_get_function,
. xlate = Exynos_gpio_ Xlate,
};
In these methods of operation, the corresponding registers of the GPIO will be directly manipulated.
Take Exynos_gpio_set_value as an example:
static int Exynos_gpio_set_value (struct udevice *dev, unsigned offset,
int value)
//With the bank corresponding to the Udevice, And the offset in the bank is the parameter
{
struct exynos_bank_info *state = Dev_get_priv (dev);//Get Platform private data, State->bank is the register address of the corresponding bank
s5p_gpio_set_value (State->bank, offset, value);
return 0;
}
static void S5p_gpio_set_value (struct s5p_gpio_bank *bank, int gpio, int en)
{
unsigned int value;
Value = Readl (&bank->dat); Read the data register in bank
value &= ~dat_mask (GPIO);
if (en)
value |= dat_set (GPIO);
Writel (value, &bank->dat); Write
}
Note that the above also provides the conversion mode Exynos_gpio_xlate, which is responsible for parsing the GPIO attributes of the DTSi. Therefore, the format of the DTSi Gpio attribute is determined by how it is parsed here.