Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OS
U-Boot.Mirror
提交
9f84da8d
U
U-Boot.Mirror
项目概览
OS
/
U-Boot.Mirror
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
U
U-Boot.Mirror
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
9f84da8d
编写于
7月 21, 2016
作者:
T
Tom Rini
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
git://git.denx.de/u-boot-tegra
上级
95d52733
2a5f7f20
变更
18
隐藏空白更改
内联
并排
Showing
18 changed file
with
943 addition
and
27 deletion
+943
-27
arch/arm/cpu/armv8/start.S
arch/arm/cpu/armv8/start.S
+9
-0
arch/arm/dts/Makefile
arch/arm/dts/Makefile
+2
-1
arch/arm/dts/tegra186-p2771-0000-a02.dts
arch/arm/dts/tegra186-p2771-0000-a02.dts
+8
-0
arch/arm/dts/tegra186-p2771-0000-b00.dts
arch/arm/dts/tegra186-p2771-0000-b00.dts
+8
-0
arch/arm/dts/tegra186-p2771-0000.dtsi
arch/arm/dts/tegra186-p2771-0000.dtsi
+0
-2
arch/arm/dts/tegra186.dtsi
arch/arm/dts/tegra186.dtsi
+1
-1
arch/arm/include/asm/arch-tegra/ivc.h
arch/arm/include/asm/arch-tegra/ivc.h
+179
-0
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/Kconfig
+9
-0
arch/arm/mach-tegra/Makefile
arch/arm/mach-tegra/Makefile
+7
-6
arch/arm/mach-tegra/board186.c
arch/arm/mach-tegra/board186.c
+0
-12
arch/arm/mach-tegra/ivc.c
arch/arm/mach-tegra/ivc.c
+553
-0
arch/arm/mach-tegra/tegra186/Makefile
arch/arm/mach-tegra/tegra186/Makefile
+2
-3
arch/arm/mach-tegra/tegra186/nvtboot_ll.S
arch/arm/mach-tegra/tegra186/nvtboot_ll.S
+20
-0
arch/arm/mach-tegra/tegra186/nvtboot_mem.c
arch/arm/mach-tegra/tegra186/nvtboot_mem.c
+88
-0
board/nvidia/p2371-2180/p2371-2180.c
board/nvidia/p2371-2180/p2371-2180.c
+22
-0
board/nvidia/p2571/max77620_init.h
board/nvidia/p2571/max77620_init.h
+2
-0
configs/p2771-0000-a02_defconfig
configs/p2771-0000-a02_defconfig
+2
-2
configs/p2771-0000-b00_defconfig
configs/p2771-0000-b00_defconfig
+31
-0
未找到文件。
arch/arm/cpu/armv8/start.S
浏览文件 @
9f84da8d
...
...
@@ -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
)
arch/arm/dts/Makefile
浏览文件 @
9f84da8d
...
...
@@ -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
\
...
...
arch/arm/dts/tegra186-p2771-0000-a02.dts
0 → 100644
浏览文件 @
9f84da8d
/
dts
-
v1
/;
#
include
"tegra186-p2771-0000.dtsi"
/
{
model
=
"NVIDIA P2771-0000 A02"
;
compatible
=
"nvidia,p2771-0000-a02"
,
"nvidia,p2771-0000"
,
"nvidia,tegra186"
;
};
arch/arm/dts/tegra186-p2771-0000-b00.dts
0 → 100644
浏览文件 @
9f84da8d
/
dts
-
v1
/;
#
include
"tegra186-p2771-0000.dtsi"
/
{
model
=
"NVIDIA P2771-0000 B00"
;
compatible
=
"nvidia,p2771-0000-b00"
,
"nvidia,p2771-0000"
,
"nvidia,tegra186"
;
};
arch/arm/dts/tegra186-p2771-0000.dts
→
arch/arm/dts/tegra186-p2771-0000.dts
i
浏览文件 @
9f84da8d
/
dts
-
v1
/;
#
include
"tegra186.dtsi"
/
{
...
...
arch/arm/dts/tegra186.dtsi
浏览文件 @
9f84da8d
#include "skeleton.dtsi"
#include <dt-bindings/gpio/tegra-gpio.h>
#include <dt-bindings/gpio/tegra
186
-gpio.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/mailbox/tegra-hsp.h>
...
...
arch/arm/include/asm/arch-tegra/ivc.h
0 → 100644
浏览文件 @
9f84da8d
/*
* 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
arch/arm/mach-tegra/Kconfig
浏览文件 @
9f84da8d
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
...
...
arch/arm/mach-tegra/Makefile
浏览文件 @
9f84da8d
...
...
@@ -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/
...
...
arch/arm/mach-tegra/board186.c
浏览文件 @
9f84da8d
...
...
@@ -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
)
{
}
...
...
arch/arm/mach-tegra/ivc.c
0 → 100644
浏览文件 @
9f84da8d
/*
* 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
;
}
arch/arm/mach-tegra/tegra186/Makefile
浏览文件 @
9f84da8d
...
...
@@ -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
arch/arm/mach-tegra/tegra186/nvtboot_ll.S
0 → 100644
浏览文件 @
9f84da8d
/*
*
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
)
arch/arm/mach-tegra/tegra186/nvtboot_mem.c
0 → 100644
浏览文件 @
9f84da8d
/*
* 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
;
}
board/nvidia/p2371-2180/p2371-2180.c
浏览文件 @
9f84da8d
...
...
@@ -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
);
}
}
/*
...
...
board/nvidia/p2571/max77620_init.h
浏览文件 @
9f84da8d
...
...
@@ -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
...
...
configs/p2771-0000_defconfig
→
configs/p2771-0000
-a02
_defconfig
浏览文件 @
9f84da8d
...
...
@@ -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
...
...
configs/p2771-0000-b00_defconfig
0 → 100644
浏览文件 @
9f84da8d
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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录