Merge branch 'rpi-2023.04' of https://source.denx.de/u-boot/custodians/u-boot-raspberrypi
- Fixes for booting newer revs of the SoC in the Raspberry Pi 4 - Propagate some firmware DT properties to the loaded DT - Update the Zero2W upstream DT name
This commit is contained in:
commit
78f67f11a9
|
|
@ -224,6 +224,8 @@ struct bcm2835_mbox_tag_set_power_state {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002
|
#define BCM2835_MBOX_TAG_GET_CLOCK_RATE 0x00030002
|
||||||
|
#define BCM2835_MBOX_TAG_GET_MAX_CLOCK_RATE 0x00030004
|
||||||
|
#define BCM2835_MBOX_TAG_GET_MIN_CLOCK_RATE 0x00030007
|
||||||
|
|
||||||
#define BCM2835_MBOX_CLOCK_ID_EMMC 1
|
#define BCM2835_MBOX_CLOCK_ID_EMMC 1
|
||||||
#define BCM2835_MBOX_CLOCK_ID_UART 2
|
#define BCM2835_MBOX_CLOCK_ID_UART 2
|
||||||
|
|
@ -250,6 +252,22 @@ struct bcm2835_mbox_tag_get_clock_rate {
|
||||||
} body;
|
} body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BCM2835_MBOX_TAG_SET_SDHOST_CLOCK 0x00038042
|
||||||
|
|
||||||
|
struct bcm2835_mbox_tag_set_sdhost_clock {
|
||||||
|
struct bcm2835_mbox_tag_hdr tag_hdr;
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
u32 rate_hz;
|
||||||
|
} req;
|
||||||
|
struct {
|
||||||
|
u32 rate_hz;
|
||||||
|
u32 rate_1;
|
||||||
|
u32 rate_2;
|
||||||
|
} resp;
|
||||||
|
} body;
|
||||||
|
};
|
||||||
|
|
||||||
#define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001
|
#define BCM2835_MBOX_TAG_ALLOCATE_BUFFER 0x00040001
|
||||||
|
|
||||||
struct bcm2835_mbox_tag_allocate_buffer {
|
struct bcm2835_mbox_tag_allocate_buffer {
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,16 @@ int bcm2835_power_on_module(u32 module);
|
||||||
*/
|
*/
|
||||||
int bcm2835_get_mmc_clock(u32 clock_id);
|
int bcm2835_get_mmc_clock(u32 clock_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bcm2835_set_sdhost_clock() - determine if firmware controls sdhost cdiv
|
||||||
|
*
|
||||||
|
* @rate_hz: Input clock frequency
|
||||||
|
* @rate_1: Returns a clock frequency
|
||||||
|
* @rate_2: Returns a clock frequency
|
||||||
|
* @return 0 of OK, -EIO on error
|
||||||
|
*/
|
||||||
|
int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bcm2835_get_video_size() - get the current display size
|
* bcm2835_get_video_size() - get the current display size
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,12 @@ struct msg_get_clock_rate {
|
||||||
u32 end_tag;
|
u32 end_tag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct msg_set_sdhost_clock {
|
||||||
|
struct bcm2835_mbox_hdr hdr;
|
||||||
|
struct bcm2835_mbox_tag_set_sdhost_clock set_sdhost_clock;
|
||||||
|
u32 end_tag;
|
||||||
|
};
|
||||||
|
|
||||||
struct msg_query {
|
struct msg_query {
|
||||||
struct bcm2835_mbox_hdr hdr;
|
struct bcm2835_mbox_hdr hdr;
|
||||||
struct bcm2835_mbox_tag_physical_w_h physical_w_h;
|
struct bcm2835_mbox_tag_physical_w_h physical_w_h;
|
||||||
|
|
@ -75,6 +81,7 @@ int bcm2835_get_mmc_clock(u32 clock_id)
|
||||||
{
|
{
|
||||||
ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
|
ALLOC_CACHE_ALIGN_BUFFER(struct msg_get_clock_rate, msg_clk, 1);
|
||||||
int ret;
|
int ret;
|
||||||
|
u32 clock_rate = 0;
|
||||||
|
|
||||||
ret = bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
|
ret = bcm2835_power_on_module(BCM2835_MBOX_POWER_DEVID_SDHCI);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
@ -90,7 +97,45 @@ int bcm2835_get_mmc_clock(u32 clock_id)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg_clk->get_clock_rate.body.resp.rate_hz;
|
clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
|
||||||
|
|
||||||
|
if (clock_rate == 0) {
|
||||||
|
BCM2835_MBOX_INIT_HDR(msg_clk);
|
||||||
|
BCM2835_MBOX_INIT_TAG(&msg_clk->get_clock_rate, GET_MAX_CLOCK_RATE);
|
||||||
|
msg_clk->get_clock_rate.body.req.clock_id = clock_id;
|
||||||
|
|
||||||
|
ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_clk->hdr);
|
||||||
|
if (ret) {
|
||||||
|
printf("bcm2835: Could not query max eMMC clock rate\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
clock_rate = msg_clk->get_clock_rate.body.resp.rate_hz;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clock_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bcm2835_set_sdhost_clock(u32 rate_hz, u32 *rate_1, u32 *rate_2)
|
||||||
|
{
|
||||||
|
ALLOC_CACHE_ALIGN_BUFFER(struct msg_set_sdhost_clock, msg_sdhost_clk, 1);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
BCM2835_MBOX_INIT_HDR(msg_sdhost_clk);
|
||||||
|
BCM2835_MBOX_INIT_TAG(&msg_sdhost_clk->set_sdhost_clock, SET_SDHOST_CLOCK);
|
||||||
|
|
||||||
|
msg_sdhost_clk->set_sdhost_clock.body.req.rate_hz = rate_hz;
|
||||||
|
|
||||||
|
ret = bcm2835_mbox_call_prop(BCM2835_MBOX_PROP_CHAN, &msg_sdhost_clk->hdr);
|
||||||
|
if (ret) {
|
||||||
|
printf("bcm2835: Could not query sdhost clock rate\n");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
*rate_1 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_1;
|
||||||
|
*rate_2 = msg_sdhost_clk->set_sdhost_clock.body.resp.rate_2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bcm2835_get_video_size(int *widthp, int *heightp)
|
int bcm2835_get_video_size(int *widthp, int *heightp)
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ static const struct rpi_model rpi_models_new_scheme[] = {
|
||||||
},
|
},
|
||||||
[0x12] = {
|
[0x12] = {
|
||||||
"Zero 2 W",
|
"Zero 2 W",
|
||||||
DTB_DIR "bcm2837-rpi-zero-2.dtb",
|
DTB_DIR "bcm2837-rpi-zero-2-w.dtb",
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
[0x13] = {
|
[0x13] = {
|
||||||
|
|
@ -503,10 +503,61 @@ void *board_fdt_blob_setup(int *err)
|
||||||
return (void *)fw_dtb_pointer;
|
return (void *)fw_dtb_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int copy_property(void *dst, void *src, char *path, char *property)
|
||||||
|
{
|
||||||
|
int dst_offset, src_offset;
|
||||||
|
const fdt32_t *prop;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
src_offset = fdt_path_offset(src, path);
|
||||||
|
dst_offset = fdt_path_offset(dst, path);
|
||||||
|
|
||||||
|
if (src_offset < 0 || dst_offset < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
prop = fdt_getprop(src, src_offset, property, &len);
|
||||||
|
if (!prop)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return fdt_setprop(dst, dst_offset, property, prop, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy tweaks from the firmware dtb to the loaded dtb */
|
||||||
|
void update_fdt_from_fw(void *fdt, void *fw_fdt)
|
||||||
|
{
|
||||||
|
/* Using dtb from firmware directly; leave it alone */
|
||||||
|
if (fdt == fw_fdt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* The firmware provides a more precie model; so copy that */
|
||||||
|
copy_property(fdt, fw_fdt, "/", "model");
|
||||||
|
|
||||||
|
/* memory reserve as suggested by the firmware */
|
||||||
|
copy_property(fdt, fw_fdt, "/", "memreserve");
|
||||||
|
|
||||||
|
/* Adjust dma-ranges for the SD card and PCI bus as they can depend on
|
||||||
|
* the SoC revision
|
||||||
|
*/
|
||||||
|
copy_property(fdt, fw_fdt, "emmc2bus", "dma-ranges");
|
||||||
|
copy_property(fdt, fw_fdt, "pcie0", "dma-ranges");
|
||||||
|
|
||||||
|
/* Bootloader configuration template exposes as nvmem */
|
||||||
|
if (copy_property(fdt, fw_fdt, "blconfig", "reg") == 0)
|
||||||
|
copy_property(fdt, fw_fdt, "blconfig", "status");
|
||||||
|
|
||||||
|
/* kernel address randomisation seed as provided by the firmware */
|
||||||
|
copy_property(fdt, fw_fdt, "/chosen", "kaslr-seed");
|
||||||
|
|
||||||
|
/* address of the PHY device as provided by the firmware */
|
||||||
|
copy_property(fdt, fw_fdt, "ethernet0/mdio@e14/ethernet-phy@1", "reg");
|
||||||
|
}
|
||||||
|
|
||||||
int ft_board_setup(void *blob, struct bd_info *bd)
|
int ft_board_setup(void *blob, struct bd_info *bd)
|
||||||
{
|
{
|
||||||
int node;
|
int node;
|
||||||
|
|
||||||
|
update_fdt_from_fw(blob, (void *)fw_dtb_pointer);
|
||||||
|
|
||||||
node = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer");
|
node = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer");
|
||||||
if (node < 0)
|
if (node < 0)
|
||||||
fdt_simplefb_add_node(blob);
|
fdt_simplefb_add_node(blob);
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ struct bcm2835_host {
|
||||||
struct udevice *dev;
|
struct udevice *dev;
|
||||||
struct mmc *mmc;
|
struct mmc *mmc;
|
||||||
struct bcm2835_plat *plat;
|
struct bcm2835_plat *plat;
|
||||||
|
unsigned int firmware_sets_cdiv:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void bcm2835_dumpregs(struct bcm2835_host *host)
|
static void bcm2835_dumpregs(struct bcm2835_host *host)
|
||||||
|
|
@ -233,7 +234,7 @@ static void bcm2835_reset_internal(struct bcm2835_host *host)
|
||||||
msleep(20);
|
msleep(20);
|
||||||
host->clock = 0;
|
host->clock = 0;
|
||||||
writel(host->hcfg, host->ioaddr + SDHCFG);
|
writel(host->hcfg, host->ioaddr + SDHCFG);
|
||||||
writel(host->cdiv, host->ioaddr + SDCDIV);
|
writel(SDCDIV_MAX_CDIV, host->ioaddr + SDCDIV);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm2835_wait_transfer_complete(struct bcm2835_host *host)
|
static int bcm2835_wait_transfer_complete(struct bcm2835_host *host)
|
||||||
|
|
@ -598,6 +599,7 @@ static int bcm2835_transmit(struct bcm2835_host *host)
|
||||||
static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
|
static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
|
||||||
{
|
{
|
||||||
int div;
|
int div;
|
||||||
|
u32 clock_rate[2] = { 0 };
|
||||||
|
|
||||||
/* The SDCDIV register has 11 bits, and holds (div - 2). But
|
/* The SDCDIV register has 11 bits, and holds (div - 2). But
|
||||||
* in data mode the max is 50MHz wihout a minimum, and only
|
* in data mode the max is 50MHz wihout a minimum, and only
|
||||||
|
|
@ -620,26 +622,34 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
|
||||||
* clock divisor at all times.
|
* clock divisor at all times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (clock < 100000) {
|
if (host->firmware_sets_cdiv) {
|
||||||
/* Can't stop the clock, but make it as slow as possible
|
bcm2835_set_sdhost_clock(clock, &clock_rate[0], &clock_rate[1]);
|
||||||
* to show willing
|
clock = max(clock_rate[0], clock_rate[1]);
|
||||||
*/
|
} else {
|
||||||
host->cdiv = SDCDIV_MAX_CDIV;
|
if (clock < 100000) {
|
||||||
|
/* Can't stop the clock, but make it as slow as possible
|
||||||
|
* to show willing
|
||||||
|
*/
|
||||||
|
host->cdiv = SDCDIV_MAX_CDIV;
|
||||||
|
writel(host->cdiv, host->ioaddr + SDCDIV);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
div = host->max_clk / clock;
|
||||||
|
if (div < 2)
|
||||||
|
div = 2;
|
||||||
|
if ((host->max_clk / div) > clock)
|
||||||
|
div++;
|
||||||
|
div -= 2;
|
||||||
|
|
||||||
|
if (div > SDCDIV_MAX_CDIV)
|
||||||
|
div = SDCDIV_MAX_CDIV;
|
||||||
|
|
||||||
|
clock = host->max_clk / (div + 2);
|
||||||
|
host->cdiv = div;
|
||||||
writel(host->cdiv, host->ioaddr + SDCDIV);
|
writel(host->cdiv, host->ioaddr + SDCDIV);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
div = host->max_clk / clock;
|
|
||||||
if (div < 2)
|
|
||||||
div = 2;
|
|
||||||
if ((host->max_clk / div) > clock)
|
|
||||||
div++;
|
|
||||||
div -= 2;
|
|
||||||
|
|
||||||
if (div > SDCDIV_MAX_CDIV)
|
|
||||||
div = SDCDIV_MAX_CDIV;
|
|
||||||
|
|
||||||
clock = host->max_clk / (div + 2);
|
|
||||||
host->mmc->clock = clock;
|
host->mmc->clock = clock;
|
||||||
|
|
||||||
/* Calibrate some delays */
|
/* Calibrate some delays */
|
||||||
|
|
@ -647,9 +657,6 @@ static void bcm2835_set_clock(struct bcm2835_host *host, unsigned int clock)
|
||||||
host->ns_per_fifo_word = (1000000000 / clock) *
|
host->ns_per_fifo_word = (1000000000 / clock) *
|
||||||
((host->mmc->card_caps & MMC_MODE_4BIT) ? 8 : 32);
|
((host->mmc->card_caps & MMC_MODE_4BIT) ? 8 : 32);
|
||||||
|
|
||||||
host->cdiv = div;
|
|
||||||
writel(host->cdiv, host->ioaddr + SDCDIV);
|
|
||||||
|
|
||||||
/* Set the timeout to 500ms */
|
/* Set the timeout to 500ms */
|
||||||
writel(host->mmc->clock / 2, host->ioaddr + SDTOUT);
|
writel(host->mmc->clock / 2, host->ioaddr + SDTOUT);
|
||||||
}
|
}
|
||||||
|
|
@ -759,6 +766,7 @@ static int bcm2835_probe(struct udevice *dev)
|
||||||
struct bcm2835_host *host = dev_get_priv(dev);
|
struct bcm2835_host *host = dev_get_priv(dev);
|
||||||
struct mmc *mmc = mmc_get_mmc_dev(dev);
|
struct mmc *mmc = mmc_get_mmc_dev(dev);
|
||||||
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
|
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
|
||||||
|
u32 clock_rate[2] = { ~0 };
|
||||||
|
|
||||||
host->dev = dev;
|
host->dev = dev;
|
||||||
host->mmc = mmc;
|
host->mmc = mmc;
|
||||||
|
|
@ -776,6 +784,9 @@ static int bcm2835_probe(struct udevice *dev)
|
||||||
|
|
||||||
host->max_clk = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_CORE);
|
host->max_clk = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_CORE);
|
||||||
|
|
||||||
|
bcm2835_set_sdhost_clock(0, &clock_rate[0], &clock_rate[1]);
|
||||||
|
host->firmware_sets_cdiv = (clock_rate[0] != ~0);
|
||||||
|
|
||||||
bcm2835_add_host(host);
|
bcm2835_add_host(host);
|
||||||
|
|
||||||
dev_dbg(dev, "%s -> OK\n", __func__);
|
dev_dbg(dev, "%s -> OK\n", __func__);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue