提交 9f84da8d 编写于 作者: T Tom Rini

Merge branch 'master' of git://git.denx.de/u-boot-tegra

......@@ -53,6 +53,11 @@ _bss_end_ofs:
.quad __bss_end - _start
reset:
/* Allow the board to save important registers */
b save_boot_params
.globl save_boot_params_ret
save_boot_params_ret:
#ifdef CONFIG_SYS_RESET_SCTRL
bl reset_sctrl
#endif
......@@ -282,3 +287,7 @@ ENTRY(c_runtime_cpu_setup)
ret
ENDPROC(c_runtime_cpu_setup)
WEAK(save_boot_params)
b save_boot_params_ret /* back to my caller */
ENDPROC(save_boot_params)
......@@ -53,7 +53,8 @@ dtb-$(CONFIG_TEGRA) += tegra20-harmony.dtb \
tegra124-jetson-tk1.dtb \
tegra124-nyan-big.dtb \
tegra124-venice2.dtb \
tegra186-p2771-0000.dtb \
tegra186-p2771-0000-a02.dtb \
tegra186-p2771-0000-b00.dtb \
tegra210-e2220-1170.dtb \
tegra210-p2371-0000.dtb \
tegra210-p2371-2180.dtb \
......
/dts-v1/;
#include "tegra186-p2771-0000.dtsi"
/ {
model = "NVIDIA P2771-0000 A02";
compatible = "nvidia,p2771-0000-a02", "nvidia,p2771-0000", "nvidia,tegra186";
};
/dts-v1/;
#include "tegra186-p2771-0000.dtsi"
/ {
model = "NVIDIA P2771-0000 B00";
compatible = "nvidia,p2771-0000-b00", "nvidia,p2771-0000", "nvidia,tegra186";
};
#include "skeleton.dtsi"
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/gpio/tegra186-gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/tegra-hsp.h>
......
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0
*/
#ifndef _ASM_ARCH_TEGRA_IVC_H
#define _ASM_ARCH_TEGRA_IVC_H
#include <common.h>
/*
* Tegra IVC is a communication protocol that transfers fixed-size frames
* bi-directionally and in-order between the local CPU and some remote entity.
* Communication is via a statically sized and allocated buffer in shared
* memory and a notification mechanism.
*
* This API handles all aspects of the shared memory buffer's metadata, and
* leaves all aspects of the frame content to the calling code; frames
* typically contain some higher-level protocol. The notification mechanism is
* also handled externally to this API, since it can vary from instance to
* instance.
*
* The client model is to first find some free (for TX) or filled (for RX)
* frame, process that frame's memory buffer (fill or read it), and then
* inform the protocol that the frame has been filled/read, i.e. advance the
* write/read pointer. If the channel is full, there may be no available frames
* to fill/read. In this case, client code may either poll for an available
* frame, or wait for the remote entity to send a notification to the local
* CPU.
*/
/**
* struct tegra_ivc - In-memory shared memory layout.
*
* This is described in detail in ivc.c.
*/
struct tegra_ivc_channel_header;
/**
* struct tegra_ivc - Software state of an IVC channel.
*
* This state is internal to the IVC code and should not be accessed directly
* by clients. It is public solely so clients can allocate storage for the
* structure.
*/
struct tegra_ivc {
/**
* rx_channel - Pointer to the shared memory region used to receive
* messages from the remote entity.
*/
struct tegra_ivc_channel_header *rx_channel;
/**
* tx_channel - Pointer to the shared memory region used to send
* messages to the remote entity.
*/
struct tegra_ivc_channel_header *tx_channel;
/**
* r_pos - The position in list of frames in rx_channel that we are
* reading from.
*/
uint32_t r_pos;
/**
* w_pos - The position in list of frames in tx_channel that we are
* writing to.
*/
uint32_t w_pos;
/**
* nframes - The number of frames allocated (in each direction) in
* shared memory.
*/
uint32_t nframes;
/**
* frame_size - The size of each frame in shared memory.
*/
uint32_t frame_size;
/**
* notify - Function to call to notify the remote processor of a
* change in channel state.
*/
void (*notify)(struct tegra_ivc *);
};
/**
* tegra_ivc_read_get_next_frame - Locate the next frame to receive.
*
* Locate the next frame to be received/processed, return the address of the
* frame, and do not remove it from the queue. Repeated calls to this function
* will return the same address until tegra_ivc_read_advance() is called.
*
* @ivc The IVC channel.
* @frame Pointer to be filled with the address of the frame to receive.
*
* @return 0 if a frame is available, else a negative error code.
*/
int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, void **frame);
/**
* tegra_ivc_read_advance - Advance the read queue.
*
* Inform the protocol and remote entity that the frame returned by
* tegra_ivc_read_get_next_frame() has been processed. The remote end may then
* re-use it to transmit further data. Subsequent to this function returning,
* tegra_ivc_read_get_next_frame() will return a different frame.
*
* @ivc The IVC channel.
*
* @return 0 if OK, else a negative error code.
*/
int tegra_ivc_read_advance(struct tegra_ivc *ivc);
/**
* tegra_ivc_write_get_next_frame - Locate the next frame to fill for transmit.
*
* Locate the next frame to be filled for transmit, return the address of the
* frame, and do not add it to the queue. Repeated calls to this function
* will return the same address until tegra_ivc_read_advance() is called.
*
* @ivc The IVC channel.
* @frame Pointer to be filled with the address of the frame to fill.
*
* @return 0 if a frame is available, else a negative error code.
*/
int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, void **frame);
/**
* tegra_ivc_write_advance - Advance the write queue.
*
* Inform the protocol and remote entity that the frame returned by
* tegra_ivc_write_get_next_frame() has been filled and should be transmitted.
* The remote end may then read data from it. Subsequent to this function
* returning, tegra_ivc_write_get_next_frame() will return a different frame.
*
* @ivc The IVC channel.
*
* @return 0 if OK, else a negative error code.
*/
int tegra_ivc_write_advance(struct tegra_ivc *ivc);
/**
* tegra_ivc_channel_notified - handle internal messages
*
* This function must be called following every notification.
*
* @ivc The IVC channel.
*
* @return 0 if the channel is ready for communication, or -EAGAIN if a
* channel reset is in progress.
*/
int tegra_ivc_channel_notified(struct tegra_ivc *ivc);
/**
* tegra_ivc_channel_reset - initiates a reset of the shared memory state
*
* This function must be called after a channel is initialized but before it
* is used for communication. The channel will be ready for use when a
* subsequent call to notify the remote of the channel reset indicates the
* reset operation is complete.
*
* @ivc The IVC channel.
*/
void tegra_ivc_channel_reset(struct tegra_ivc *ivc);
/**
* tegra_ivc_init - Initialize a channel's software state.
*
* @ivc The IVC channel.
* @rx_base Address of the the RX shared memory buffer.
* @tx_base Address of the the TX shared memory buffer.
* @nframes Number of frames in each shared memory buffer.
* @frame_size Size of each frame.
*
* @return 0 if OK, else a negative error code.
*/
int tegra_ivc_init(struct tegra_ivc *ivc, ulong rx_base, ulong tx_base,
uint32_t nframes, uint32_t frame_size,
void (*notify)(struct tegra_ivc *));
#endif
if TEGRA
config TEGRA_IVC
bool "Tegra IVC protocol"
help
IVC (Inter-VM Communication) protocol is a Tegra-specific IPC
(Inter Processor Communication) framework. Within the context of
U-Boot, it is typically used for communication between the main CPU
and various auxiliary processors.
config TEGRA_COMMON
bool "Tegra common options"
select DM
......@@ -60,6 +68,7 @@ config TEGRA186
select TEGRA186_GPIO
select TEGRA_ARMV8_COMMON
select TEGRA_HSP
select TEGRA_IVC
endchoice
......
......@@ -15,23 +15,24 @@ else
obj-$(CONFIG_CMD_ENTERRCM) += cmd_enterrcm.o
endif
obj-$(CONFIG_ARM64) += arm64-mmu.o
obj-y += ap.o
obj-y += board.o board2.o
obj-y += cache.o
obj-y += clock.o
obj-y += lowlevel_init.o
obj-y += pinmux-common.o
obj-y += powergate.o
obj-y += xusb-padctl-dummy.o
obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
obj-$(CONFIG_TEGRA_GPU) += gpu.o
obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
endif
obj-$(CONFIG_ARM64) += arm64-mmu.o
obj-$(CONFIG_TEGRA_CLOCK_SCALING) += emc.o
obj-$(CONFIG_TEGRA_GPU) += gpu.o
obj-$(CONFIG_TEGRA_IVC) += ivc.o
obj-y += lowlevel_init.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_ARMV7_PSCI) += psci.o
endif
endif
obj-$(CONFIG_DISPLAY_CPUINFO) += sys_info.o
obj-$(CONFIG_TEGRA20) += tegra20/
obj-$(CONFIG_TEGRA30) += tegra30/
......
......@@ -11,12 +11,6 @@
DECLARE_GLOBAL_DATA_PTR;
int dram_init(void)
{
gd->ram_size = (1.5 * 1024 * 1024 * 1024);
return 0;
}
int board_early_init_f(void)
{
return 0;
......@@ -32,12 +26,6 @@ int board_late_init(void)
return 0;
}
void dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = gd->ram_size;
}
void pad_init_mmc(struct mmc_host *host)
{
}
......
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <asm/io.h>
#include <asm/arch-tegra/ivc.h>
#define TEGRA_IVC_ALIGN 64
/*
* IVC channel reset protocol.
*
* Each end uses its tx_channel.state to indicate its synchronization state.
*/
enum ivc_state {
/*
* This value is zero for backwards compatibility with services that
* assume channels to be initially zeroed. Such channels are in an
* initially valid state, but cannot be asynchronously reset, and must
* maintain a valid state at all times.
*
* The transmitting end can enter the established state from the sync or
* ack state when it observes the receiving endpoint in the ack or
* established state, indicating that has cleared the counters in our
* rx_channel.
*/
ivc_state_established = 0,
/*
* If an endpoint is observed in the sync state, the remote endpoint is
* allowed to clear the counters it owns asynchronously with respect to
* the current endpoint. Therefore, the current endpoint is no longer
* allowed to communicate.
*/
ivc_state_sync,
/*
* When the transmitting end observes the receiving end in the sync
* state, it can clear the w_count and r_count and transition to the ack
* state. If the remote endpoint observes us in the ack state, it can
* return to the established state once it has cleared its counters.
*/
ivc_state_ack
};
/*
* This structure is divided into two-cache aligned parts, the first is only
* written through the tx_channel pointer, while the second is only written
* through the rx_channel pointer. This delineates ownership of the cache lines,
* which is critical to performance and necessary in non-cache coherent
* implementations.
*/
struct tegra_ivc_channel_header {
union {
/* fields owned by the transmitting end */
struct {
uint32_t w_count;
uint32_t state;
};
uint8_t w_align[TEGRA_IVC_ALIGN];
};
union {
/* fields owned by the receiving end */
uint32_t r_count;
uint8_t r_align[TEGRA_IVC_ALIGN];
};
};
static inline void tegra_ivc_invalidate_counter(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *h,
ulong offset)
{
ulong base = ((ulong)h) + offset;
invalidate_dcache_range(base, base + TEGRA_IVC_ALIGN);
}
static inline void tegra_ivc_flush_counter(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *h,
ulong offset)
{
ulong base = ((ulong)h) + offset;
flush_dcache_range(base, base + TEGRA_IVC_ALIGN);
}
static inline ulong tegra_ivc_frame_addr(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *h,
uint32_t frame)
{
BUG_ON(frame >= ivc->nframes);
return ((ulong)h) + sizeof(struct tegra_ivc_channel_header) +
(ivc->frame_size * frame);
}
static inline void *tegra_ivc_frame_pointer(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *ch,
uint32_t frame)
{
return (void *)tegra_ivc_frame_addr(ivc, ch, frame);
}
static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *h,
unsigned frame)
{
ulong base = tegra_ivc_frame_addr(ivc, h, frame);
invalidate_dcache_range(base, base + ivc->frame_size);
}
static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *h,
unsigned frame)
{
ulong base = tegra_ivc_frame_addr(ivc, h, frame);
flush_dcache_range(base, base + ivc->frame_size);
}
static inline int tegra_ivc_channel_empty(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *ch)
{
/*
* This function performs multiple checks on the same values with
* security implications, so create snapshots with ACCESS_ONCE() to
* ensure that these checks use the same values.
*/
uint32_t w_count = ACCESS_ONCE(ch->w_count);
uint32_t r_count = ACCESS_ONCE(ch->r_count);
/*
* Perform an over-full check to prevent denial of service attacks where
* a server could be easily fooled into believing that there's an
* extremely large number of frames ready, since receivers are not
* expected to check for full or over-full conditions.
*
* Although the channel isn't empty, this is an invalid case caused by
* a potentially malicious peer, so returning empty is safer, because it
* gives the impression that the channel has gone silent.
*/
if (w_count - r_count > ivc->nframes)
return 1;
return w_count == r_count;
}
static inline int tegra_ivc_channel_full(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *ch)
{
/*
* Invalid cases where the counters indicate that the queue is over
* capacity also appear full.
*/
return (ACCESS_ONCE(ch->w_count) - ACCESS_ONCE(ch->r_count)) >=
ivc->nframes;
}
static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
{
ACCESS_ONCE(ivc->rx_channel->r_count) =
ACCESS_ONCE(ivc->rx_channel->r_count) + 1;
if (ivc->r_pos == ivc->nframes - 1)
ivc->r_pos = 0;
else
ivc->r_pos++;
}
static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
{
ACCESS_ONCE(ivc->tx_channel->w_count) =
ACCESS_ONCE(ivc->tx_channel->w_count) + 1;
if (ivc->w_pos == ivc->nframes - 1)
ivc->w_pos = 0;
else
ivc->w_pos++;
}
static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
{
ulong offset;
/*
* tx_channel->state is set locally, so it is not synchronized with
* state from the remote peer. The remote peer cannot reset its
* transmit counters until we've acknowledged its synchronization
* request, so no additional synchronization is required because an
* asynchronous transition of rx_channel->state to ivc_state_ack is not
* allowed.
*/
if (ivc->tx_channel->state != ivc_state_established)
return -ECONNRESET;
/*
* Avoid unnecessary invalidations when performing repeated accesses to
* an IVC channel by checking the old queue pointers first.
* Synchronization is only necessary when these pointers indicate empty
* or full.
*/
if (!tegra_ivc_channel_empty(ivc, ivc->rx_channel))
return 0;
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
return tegra_ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0;
}
static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
{
ulong offset;
if (ivc->tx_channel->state != ivc_state_established)
return -ECONNRESET;
if (!tegra_ivc_channel_full(ivc, ivc->tx_channel))
return 0;
offset = offsetof(struct tegra_ivc_channel_header, r_count);
tegra_ivc_invalidate_counter(ivc, ivc->tx_channel, offset);
return tegra_ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0;
}
static inline uint32_t tegra_ivc_channel_avail_count(struct tegra_ivc *ivc,
struct tegra_ivc_channel_header *ch)
{
/*
* This function isn't expected to be used in scenarios where an
* over-full situation can lead to denial of service attacks. See the
* comment in tegra_ivc_channel_empty() for an explanation about
* special over-full considerations.
*/
return ACCESS_ONCE(ch->w_count) - ACCESS_ONCE(ch->r_count);
}
int tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc, void **frame)
{
int result = tegra_ivc_check_read(ivc);
if (result < 0)
return result;
/*
* Order observation of w_pos potentially indicating new data before
* data read.
*/
mb();
tegra_ivc_invalidate_frame(ivc, ivc->rx_channel, ivc->r_pos);
*frame = tegra_ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
return 0;
}
int tegra_ivc_read_advance(struct tegra_ivc *ivc)
{
ulong offset;
int result;
/*
* No read barriers or synchronization here: the caller is expected to
* have already observed the channel non-empty. This check is just to
* catch programming errors.
*/
result = tegra_ivc_check_read(ivc);
if (result)
return result;
tegra_ivc_advance_rx(ivc);
offset = offsetof(struct tegra_ivc_channel_header, r_count);
tegra_ivc_flush_counter(ivc, ivc->rx_channel, offset);
/*
* Ensure our write to r_pos occurs before our read from w_pos.
*/
mb();
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
if (tegra_ivc_channel_avail_count(ivc, ivc->rx_channel) ==
ivc->nframes - 1)
ivc->notify(ivc);
return 0;
}
int tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc, void **frame)
{
int result = tegra_ivc_check_write(ivc);
if (result)
return result;
*frame = tegra_ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
return 0;
}
int tegra_ivc_write_advance(struct tegra_ivc *ivc)
{
ulong offset;
int result;
result = tegra_ivc_check_write(ivc);
if (result)
return result;
tegra_ivc_flush_frame(ivc, ivc->tx_channel, ivc->w_pos);
/*
* Order any possible stores to the frame before update of w_pos.
*/
mb();
tegra_ivc_advance_tx(ivc);
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
/*
* Ensure our write to w_pos occurs before our read from r_pos.
*/
mb();
offset = offsetof(struct tegra_ivc_channel_header, r_count);
tegra_ivc_invalidate_counter(ivc, ivc->tx_channel, offset);
if (tegra_ivc_channel_avail_count(ivc, ivc->tx_channel) == 1)
ivc->notify(ivc);
return 0;
}
/*
* ===============================================================
* IVC State Transition Table - see tegra_ivc_channel_notified()
* ===============================================================
*
* local remote action
* ----- ------ -----------------------------------
* SYNC EST <none>
* SYNC ACK reset counters; move to EST; notify
* SYNC SYNC reset counters; move to ACK; notify
* ACK EST move to EST; notify
* ACK ACK move to EST; notify
* ACK SYNC reset counters; move to ACK; notify
* EST EST <none>
* EST ACK <none>
* EST SYNC reset counters; move to ACK; notify
*
* ===============================================================
*/
int tegra_ivc_channel_notified(struct tegra_ivc *ivc)
{
ulong offset;
enum ivc_state peer_state;
/* Copy the receiver's state out of shared memory. */
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_invalidate_counter(ivc, ivc->rx_channel, offset);
peer_state = ACCESS_ONCE(ivc->rx_channel->state);
if (peer_state == ivc_state_sync) {
/*
* Order observation of ivc_state_sync before stores clearing
* tx_channel.
*/
mb();
/*
* Reset tx_channel counters. The remote end is in the SYNC
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx_channel->w_count = 0;
ivc->rx_channel->r_count = 0;
ivc->w_pos = 0;
ivc->r_pos = 0;
/*
* Ensure that counters appear cleared before new state can be
* observed.
*/
mb();
/*
* Move to ACK state. We have just cleared our counters, so it
* is now safe for the remote end to start using these values.
*/
ivc->tx_channel->state = ivc_state_ack;
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else if (ivc->tx_channel->state == ivc_state_sync &&
peer_state == ivc_state_ack) {
/*
* Order observation of ivc_state_sync before stores clearing
* tx_channel.
*/
mb();
/*
* Reset tx_channel counters. The remote end is in the ACK
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx_channel->w_count = 0;
ivc->rx_channel->r_count = 0;
ivc->w_pos = 0;
ivc->r_pos = 0;
/*
* Ensure that counters appear cleared before new state can be
* observed.
*/
mb();
/*
* Move to ESTABLISHED state. We know that the remote end has
* already cleared its counters, so it is safe to start
* writing/reading on this channel.
*/
ivc->tx_channel->state = ivc_state_established;
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else if (ivc->tx_channel->state == ivc_state_ack) {
/*
* At this point, we have observed the peer to be in either
* the ACK or ESTABLISHED state. Next, order observation of
* peer state before storing to tx_channel.
*/
mb();
/*
* Move to ESTABLISHED state. We know that we have previously
* cleared our counters, and we know that the remote end has
* cleared its counters, so it is safe to start writing/reading
* on this channel.
*/
ivc->tx_channel->state = ivc_state_established;
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else {
/*
* There is no need to handle any further action. Either the
* channel is already fully established, or we are waiting for
* the remote end to catch up with our current state. Refer
* to the diagram in "IVC State Transition Table" above.
*/
}
if (ivc->tx_channel->state != ivc_state_established)
return -EAGAIN;
return 0;
}
void tegra_ivc_channel_reset(struct tegra_ivc *ivc)
{
ulong offset;
ivc->tx_channel->state = ivc_state_sync;
offset = offsetof(struct tegra_ivc_channel_header, w_count);
tegra_ivc_flush_counter(ivc, ivc->tx_channel, offset);
ivc->notify(ivc);
}
static int check_ivc_params(ulong qbase1, ulong qbase2, uint32_t nframes,
uint32_t frame_size)
{
int ret = 0;
BUG_ON(offsetof(struct tegra_ivc_channel_header, w_count) &
(TEGRA_IVC_ALIGN - 1));
BUG_ON(offsetof(struct tegra_ivc_channel_header, r_count) &
(TEGRA_IVC_ALIGN - 1));
BUG_ON(sizeof(struct tegra_ivc_channel_header) &
(TEGRA_IVC_ALIGN - 1));
if ((uint64_t)nframes * (uint64_t)frame_size >= 0x100000000) {
error("tegra_ivc: nframes * frame_size overflows\n");
return -EINVAL;
}
/*
* The headers must at least be aligned enough for counters
* to be accessed atomically.
*/
if ((qbase1 & (TEGRA_IVC_ALIGN - 1)) ||
(qbase2 & (TEGRA_IVC_ALIGN - 1))) {
error("tegra_ivc: channel start not aligned\n");
return -EINVAL;
}
if (frame_size & (TEGRA_IVC_ALIGN - 1)) {
error("tegra_ivc: frame size not adequately aligned\n");
return -EINVAL;
}
if (qbase1 < qbase2) {
if (qbase1 + frame_size * nframes > qbase2)
ret = -EINVAL;
} else {
if (qbase2 + frame_size * nframes > qbase1)
ret = -EINVAL;
}
if (ret) {
error("tegra_ivc: queue regions overlap\n");
return ret;
}
return 0;
}
int tegra_ivc_init(struct tegra_ivc *ivc, ulong rx_base, ulong tx_base,
uint32_t nframes, uint32_t frame_size,
void (*notify)(struct tegra_ivc *))
{
int ret;
if (!ivc)
return -EINVAL;
ret = check_ivc_params(rx_base, tx_base, nframes, frame_size);
if (ret)
return ret;
ivc->rx_channel = (struct tegra_ivc_channel_header *)rx_base;
ivc->tx_channel = (struct tegra_ivc_channel_header *)tx_base;
ivc->w_pos = 0;
ivc->r_pos = 0;
ivc->nframes = nframes;
ivc->frame_size = frame_size;
ivc->notify = notify;
return 0;
}
......@@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: GPL-2.0
obj-y += ../arm64-mmu.o
obj-y += ../board186.o
obj-y += ../lowlevel_init.o
obj-$(CONFIG_DISPLAY_CPUINFO) += ../sys_info.o
obj-y += nvtboot_ll.o
obj-y += nvtboot_mem.o
/*
* Save nvtboot-related boot-time CPU state
*
* (C) Copyright 2015-2016 NVIDIA Corporation <www.nvidia.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
#include <linux/linkage.h>
.globl nvtboot_boot_x0
nvtboot_boot_x0:
.dword 0
ENTRY(save_boot_params)
adr x8, nvtboot_boot_x0
str x0, [x8]
b save_boot_params_ret
ENDPROC(save_boot_params)
/*
* Copyright (c) 2016, NVIDIA CORPORATION.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <fdt_support.h>
#include <fdtdec.h>
#include <asm/arch/tegra.h>
DECLARE_GLOBAL_DATA_PTR;
extern unsigned long nvtboot_boot_x0;
/*
* A parsed version of /memory/reg from the DTB that is passed to U-Boot in x0.
*
* We only support up to two banks since that's all the binary bootloader
* ever sets. We assume bank 0 is RAM below 4G and bank 1 is RAM above 4G.
* This is all a fairly safe assumption, since the L4T kernel makes the same
* assumptions, so the bootloader is unlikely to change.
*
* This is written to before relocation, and hence cannot be in .bss, since
* .bss overlaps the DTB that's appended to the U-Boot binary. The initializer
* forces this into .data and avoids this issue. This also has the nice side-
* effect of the content being valid after relocation.
*/
static struct {
u64 start;
u64 size;
} ram_banks[2] = {{1}};
int dram_init(void)
{
unsigned int na, ns;
const void *nvtboot_blob = (void *)nvtboot_boot_x0;
int node, len, i;
const u32 *prop;
memset(ram_banks, 0, sizeof(ram_banks));
na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2);
ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2);
node = fdt_path_offset(nvtboot_blob, "/memory");
if (node < 0) {
error("Can't find /memory node in nvtboot DTB");
hang();
}
prop = fdt_getprop(nvtboot_blob, node, "reg", &len);
if (!prop) {
error("Can't find /memory/reg property in nvtboot DTB");
hang();
}
len /= (na + ns);
if (len > ARRAY_SIZE(ram_banks))
len = ARRAY_SIZE(ram_banks);
gd->ram_size = 0;
for (i = 0; i < len; i++) {
ram_banks[i].start = of_read_number(prop, na);
prop += na;
ram_banks[i].size = of_read_number(prop, ns);
prop += ns;
gd->ram_size += ram_banks[i].size;
}
return 0;
}
extern unsigned long nvtboot_boot_x0;
void dram_init_banksize(void)
{
int i;
for (i = 0; i < 2; i++) {
gd->bd->bi_dram[i].start = ram_banks[i].start;
gd->bd->bi_dram[i].size = ram_banks[i].size;
}
}
ulong board_get_usable_ram_top(ulong total_size)
{
return ram_banks[0].start + ram_banks[0].size;
}
......@@ -30,6 +30,28 @@ void pin_mux_mmc(void)
ret = dm_i2c_write(dev, MAX77620_CNFG1_L2_REG, &val, 1);
if (ret)
printf("i2c_write 0 0x3c 0x27 failed: %d\n", ret);
/* Disable LDO4 discharge */
ret = dm_i2c_read(dev, MAX77620_CNFG2_L4_REG, &val, 1);
if (ret) {
printf("i2c_read 0 0x3c 0x2c failed: %d\n", ret);
} else {
val &= ~BIT(1); /* ADE */
ret = dm_i2c_write(dev, MAX77620_CNFG2_L4_REG, &val, 1);
if (ret)
printf("i2c_write 0 0x3c 0x2c failed: %d\n", ret);
}
/* Set MBLPD */
ret = dm_i2c_read(dev, MAX77620_CNFGGLBL1_REG, &val, 1);
if (ret) {
printf("i2c_write 0 0x3c 0x00 failed: %d\n", ret);
} else {
val |= BIT(6); /* MBLPD */
ret = dm_i2c_write(dev, MAX77620_CNFGGLBL1_REG, &val, 1);
if (ret)
printf("i2c_write 0 0x3c 0x00 failed: %d\n", ret);
}
}
/*
......
......@@ -13,6 +13,8 @@
#define MAX77620_I2C_ADDR 0x78
#define MAX77620_I2C_ADDR_7BIT 0x3C
#define MAX77620_CNFGGLBL1_REG 0x00
#define MAX77620_SD0_REG 0x16
#define MAX77620_SD1_REG 0x17
#define MAX77620_SD2_REG 0x18
......
......@@ -2,10 +2,10 @@ CONFIG_ARM=y
CONFIG_TEGRA=y
CONFIG_TEGRA186=y
CONFIG_TARGET_P2771_0000=y
CONFIG_DEFAULT_DEVICE_TREE="tegra186-p2771-0000"
CONFIG_DEFAULT_DEVICE_TREE="tegra186-p2771-0000-a02"
CONFIG_OF_SYSTEM_SETUP=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="Tegra186 (P2771-0000) # "
CONFIG_SYS_PROMPT="Tegra186 (P2771-0000 A02) # "
# CONFIG_CMD_IMI is not set
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
......
CONFIG_ARM=y
CONFIG_TEGRA=y
CONFIG_TEGRA186=y
CONFIG_TARGET_P2771_0000=y
CONFIG_DEFAULT_DEVICE_TREE="tegra186-p2771-0000-b00"
CONFIG_OF_SYSTEM_SETUP=y
CONFIG_HUSH_PARSER=y
CONFIG_SYS_PROMPT="Tegra186 (P2771-0000 B00) # "
# CONFIG_CMD_IMI is not set
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_MMC=y
CONFIG_CMD_SF=y
CONFIG_CMD_SPI=y
CONFIG_CMD_I2C=y
CONFIG_CMD_USB=y
# CONFIG_CMD_FPGA is not set
CONFIG_CMD_GPIO=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_DHCP=y
# CONFIG_CMD_NFS is not set
CONFIG_CMD_MII=y
CONFIG_CMD_PING=y
CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y
CONFIG_CMD_EXT4_WRITE=y
CONFIG_CMD_FAT=y
CONFIG_CMD_FS_GENERIC=y
CONFIG_SYS_NS16550=y
CONFIG_USB=y
CONFIG_DM_USB=y
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册