Merge git://www.denx.de/git/u-boot-sunxi
This commit is contained in:
@@ -11,9 +11,25 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <dm/device-internal.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR
|
||||
|
||||
struct sunxi_gpio_platdata {
|
||||
struct sunxi_gpio *regs;
|
||||
const char *bank_name; /* Name of bank, e.g. "B" */
|
||||
int gpio_count;
|
||||
};
|
||||
|
||||
#ifndef CONFIG_DM_GPIO
|
||||
static int sunxi_gpio_output(u32 pin, u32 val)
|
||||
{
|
||||
u32 dat;
|
||||
@@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name)
|
||||
return -1;
|
||||
return group * 32 + pin;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DM_GPIO
|
||||
static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
|
||||
sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
u32 num = GPIO_NUM(offset);
|
||||
|
||||
sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT);
|
||||
clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
u32 num = GPIO_NUM(offset);
|
||||
unsigned dat;
|
||||
|
||||
dat = readl(&plat->regs->dat);
|
||||
dat >>= num;
|
||||
|
||||
return dat & 0x1;
|
||||
}
|
||||
|
||||
static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
u32 num = GPIO_NUM(offset);
|
||||
|
||||
clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
int func;
|
||||
|
||||
func = sunxi_gpio_get_cfgbank(plat->regs, offset);
|
||||
if (func == SUNXI_GPIO_OUTPUT)
|
||||
return GPIOF_OUTPUT;
|
||||
else if (func == SUNXI_GPIO_INPUT)
|
||||
return GPIOF_INPUT;
|
||||
else
|
||||
return GPIOF_FUNC;
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_sunxi_ops = {
|
||||
.direction_input = sunxi_gpio_direction_input,
|
||||
.direction_output = sunxi_gpio_direction_output,
|
||||
.get_value = sunxi_gpio_get_value,
|
||||
.set_value = sunxi_gpio_set_value,
|
||||
.get_function = sunxi_gpio_get_function,
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the name of a GPIO bank
|
||||
*
|
||||
* GPIO banks are named A, B, C, ...
|
||||
*
|
||||
* @bank: Bank number (0, 1..n-1)
|
||||
* @return allocated string containing the name
|
||||
*/
|
||||
static char *gpio_bank_name(int bank)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = malloc(2);
|
||||
if (name) {
|
||||
name[0] = 'A' + bank;
|
||||
name[1] = '\0';
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static int gpio_sunxi_probe(struct udevice *dev)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev->uclass_priv;
|
||||
|
||||
/* Tell the uclass how many GPIOs we have */
|
||||
if (plat) {
|
||||
uc_priv->gpio_count = plat->gpio_count;
|
||||
uc_priv->bank_name = plat->bank_name;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* We have a top-level GPIO device with no actual GPIOs. It has a child
|
||||
* device for each Sunxi bank.
|
||||
*/
|
||||
static int gpio_sunxi_bind(struct udevice *parent)
|
||||
{
|
||||
struct sunxi_gpio_platdata *plat = parent->platdata;
|
||||
struct sunxi_gpio_reg *ctlr;
|
||||
int bank;
|
||||
int ret;
|
||||
|
||||
/* If this is a child device, there is nothing to do here */
|
||||
if (plat)
|
||||
return 0;
|
||||
|
||||
ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
|
||||
parent->of_offset, "reg");
|
||||
for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) {
|
||||
struct sunxi_gpio_platdata *plat;
|
||||
struct udevice *dev;
|
||||
|
||||
plat = calloc(1, sizeof(*plat));
|
||||
if (!plat)
|
||||
return -ENOMEM;
|
||||
plat->regs = &ctlr->gpio_bank[bank];
|
||||
plat->bank_name = gpio_bank_name(bank);
|
||||
plat->gpio_count = SUNXI_GPIOS_PER_BANK;
|
||||
|
||||
ret = device_bind(parent, parent->driver,
|
||||
plat->bank_name, plat, -1, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
dev->of_offset = parent->of_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id sunxi_gpio_ids[] = {
|
||||
{ .compatible = "allwinner,sun7i-a20-pinctrl" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(gpio_sunxi) = {
|
||||
.name = "gpio_sunxi",
|
||||
.id = UCLASS_GPIO,
|
||||
.ops = &gpio_sunxi_ops,
|
||||
.of_match = sunxi_gpio_ids,
|
||||
.bind = gpio_sunxi_bind,
|
||||
.probe = gpio_sunxi_probe,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -30,10 +30,22 @@ struct sunxi_mmc_host {
|
||||
/* support 4 mmc hosts */
|
||||
struct sunxi_mmc_host mmc_host[4];
|
||||
|
||||
static int sunxi_mmc_getcd_gpio(int sdc_no)
|
||||
{
|
||||
switch (sdc_no) {
|
||||
case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN);
|
||||
case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN);
|
||||
case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN);
|
||||
case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mmc_resource_init(int sdc_no)
|
||||
{
|
||||
struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no];
|
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
int cd_pin, ret = 0;
|
||||
|
||||
debug("init mmc %d resource\n", sdc_no);
|
||||
|
||||
@@ -60,7 +72,11 @@ static int mmc_resource_init(int sdc_no)
|
||||
}
|
||||
mmchost->mmc_no = sdc_no;
|
||||
|
||||
return 0;
|
||||
cd_pin = sunxi_mmc_getcd_gpio(sdc_no);
|
||||
if (cd_pin != -1)
|
||||
ret = gpio_request(cd_pin, "mmc_cd");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmc_clk_io_on(int sdc_no)
|
||||
@@ -75,7 +91,7 @@ static int mmc_clk_io_on(int sdc_no)
|
||||
/* config ahb clock */
|
||||
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no));
|
||||
|
||||
#if defined(CONFIG_SUN6I) || defined(CONFIG_SUN8I)
|
||||
#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I)
|
||||
/* unassert reset */
|
||||
setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no));
|
||||
#endif
|
||||
@@ -351,15 +367,9 @@ out:
|
||||
static int sunxi_mmc_getcd(struct mmc *mmc)
|
||||
{
|
||||
struct sunxi_mmc_host *mmchost = mmc->priv;
|
||||
int cd_pin = -1;
|
||||
|
||||
switch (mmchost->mmc_no) {
|
||||
case 0: cd_pin = sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); break;
|
||||
case 1: cd_pin = sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); break;
|
||||
case 2: cd_pin = sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); break;
|
||||
case 3: cd_pin = sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); break;
|
||||
}
|
||||
int cd_pin;
|
||||
|
||||
cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no);
|
||||
if (cd_pin == -1)
|
||||
return 1;
|
||||
|
||||
@@ -385,7 +395,7 @@ struct mmc *sunxi_mmc_init(int sdc_no)
|
||||
cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
|
||||
cfg->host_caps = MMC_MODE_4BIT;
|
||||
cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
|
||||
#if defined(CONFIG_SUN6I) || defined(CONFIG_SUN7I) || defined(CONFIG_SUN8I)
|
||||
#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || defined(CONFIG_MACH_SUN8I)
|
||||
cfg->host_caps |= MMC_MODE_HC;
|
||||
#endif
|
||||
cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
|
||||
@@ -393,7 +403,9 @@ struct mmc *sunxi_mmc_init(int sdc_no)
|
||||
cfg->f_min = 400000;
|
||||
cfg->f_max = 52000000;
|
||||
|
||||
mmc_resource_init(sdc_no);
|
||||
if (mmc_resource_init(sdc_no) != 0)
|
||||
return NULL;
|
||||
|
||||
mmc_clk_io_on(sdc_no);
|
||||
|
||||
return mmc_create(cfg, &mmc_host[sdc_no]);
|
||||
|
||||
@@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o
|
||||
obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
|
||||
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
|
||||
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
|
||||
obj-$(CONFIG_DW_SERIAL) += serial_dw.o
|
||||
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
|
||||
obj-$(CONFIG_MCFUART) += mcfuart.o
|
||||
obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
|
||||
|
||||
39
drivers/serial/serial_dw.c
Normal file
39
drivers/serial/serial_dw.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Google, Inc
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <ns16550.h>
|
||||
#include <serial.h>
|
||||
|
||||
static const struct udevice_id dw_serial_ids[] = {
|
||||
{ .compatible = "snps,dw-apb-uart" },
|
||||
{ }
|
||||
};
|
||||
|
||||
static int dw_serial_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct ns16550_platdata *plat = dev_get_platdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ns16550_serial_ofdata_to_platdata(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
plat->clock = CONFIG_SYS_NS16550_CLK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(serial_ns16550) = {
|
||||
.name = "serial_dw",
|
||||
.id = UCLASS_SERIAL,
|
||||
.of_match = dw_serial_ids,
|
||||
.ofdata_to_platdata = dw_serial_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
|
||||
.priv_auto_alloc_size = sizeof(struct NS16550),
|
||||
.probe = ns16550_serial_probe,
|
||||
.ops = &ns16550_serial_ops,
|
||||
};
|
||||
@@ -105,7 +105,7 @@ static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci)
|
||||
usb_phy_write(sunxi_ehci, 0x20, 0x14, 5);
|
||||
|
||||
/* threshold adjustment disconnect */
|
||||
#ifdef CONFIG_SUN4I
|
||||
#ifdef CONFIG_MACH_SUN4I
|
||||
usb_phy_write(sunxi_ehci, 0x2a, 3, 2);
|
||||
#else
|
||||
usb_phy_write(sunxi_ehci, 0x2a, 2, 2);
|
||||
@@ -163,11 +163,16 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
|
||||
{
|
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
|
||||
int err;
|
||||
|
||||
/* enable common PHY only once */
|
||||
if (index == 0)
|
||||
setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
|
||||
|
||||
err = gpio_request(sunxi_ehci->gpio_vbus, "ehci_vbus");
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sunxi_ehci_enable(sunxi_ehci);
|
||||
|
||||
*hccr = get_io_base(sunxi_ehci->id);
|
||||
@@ -188,9 +193,14 @@ int ehci_hcd_stop(int index)
|
||||
{
|
||||
struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index];
|
||||
int err;
|
||||
|
||||
sunxi_ehci_disable(sunxi_ehci);
|
||||
|
||||
err = gpio_free(sunxi_ehci->gpio_vbus);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* disable common PHY only once, for the last enabled hcd */
|
||||
if (enabled_hcd_count == 1)
|
||||
clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE);
|
||||
|
||||
Reference in New Issue
Block a user