目录
[1. 多层多通道的互连结构](#1. 多层多通道的互连结构)
[2. 服务质量保证](#2. 服务质量保证)
[3. 专用带宽通道](#3. 专用带宽通道)
[4. 与DDR控制器的紧密耦合](#4. 与DDR控制器的紧密耦合)
[1 .U-Boot初始化配置](#1 .U-Boot初始化配置)
[2. 多媒体场景优化](#2. 多媒体场景优化)
一,NOC理论基础
在传统的SoC设计中,各个IP核(如CPU、GPU、VPU、内存控制器等)通常通过共享总线(如AMBA AXI)进行通信。但随着芯片内模块增多、数据流复杂化,总线容易成为性能瓶颈。
NOC 可以理解为 芯片内部的"高速公路网"或"交换网络"。它将多个并行的数据通道和交换节点集成在片上,允许多个主设备(如CPU、GPU)和从设备(如DDR、外部接口)之间同时进行高速、低延迟的数据传输,极大提升了内部带宽和效率。
1. 多层多通道的互连结构
NOC不是一个单一总线,而是一个分层、分区的交换网络。它通常包含:
-
多个主端口:连接不同的主设备(CPU簇、GPU、视频处理单元VPU、显示处理器VOP、各种DMA控制器等)。
-
多个从端口 :主要连接到双通道DDR内存控制器,也连接到一些高速配置总线。
-
内部的交叉开关:用于路由数据包,允许多个传输同时进行。
2. 服务质量保证
这是NOC最关键的特性。NOC实现了QoS机制:
-
带宽分配:可以为不同的主设备或数据流(如显示输出、视频解码、GPU渲染)设置不同的带宽权重或上限。
-
优先级控制:高优先级的请求(如显示实时读取帧缓冲)会被优先处理和响应,确保画面不卡顿。
-
仲裁策略:智能的仲裁器根据配置的QoS规则,决定多个并发请求的响应顺序。
3. 专用带宽通道
对于最关键的子系统使用专用数据通路来绕过公共部分的竞争:
-
显示路径:从内存到显示控制器(VOP)的读请求具有极高优先级和专用通道,这是保证UI流畅和视频播放不掉帧的基石。
-
视频编解码路径:VPU与内存之间的数据通道也经过特别优化,保证大块视频码流输入和输出帧的稳定传输。
4. 与DDR控制器的紧密耦合
NOC直接与高效的双通道32位DDR3/LPDDR2/LPDDR3内存控制器对接。NOC负责将内部多路请求,高效地调度并转换为对DDR物理层的访问命令,最大化利用DDR带宽。
二,rk3288的NOC寄存器
|---------------|---------------|------------|-------------|--------------|
| 地址偏移 | 寄存器名称 | 大小 | 复位值 | 功能描述 |
| 0x0000-0x07FF | 保留 | - | - | 保留区域 |
| 0x0800-0x08FF | QoS优先级控制 | 4字节 | 0x00000000 | 主设备优先级设置 |
| 0x0900-0x09FF | 带宽控制 | 4字节 | 0x00000000 | 带宽限制和分配 |
| 0x0A00-0x0AFF | 性能计数器 | 4字节 | 0x00000000 | 监控总线性能 |
| 0x0B00-0x0BFF | 仲裁控制 | 4字节 | 0x00000000 | 仲裁算法配置 |
| 0x0C00-0x0CFF | 状态寄存器 | 4字节 | 0x00000000 | 总线状态和错误 |
| 0x0D00-0x1FFF | 保留 | - | - | 保留区域 |
1,QoS优先级寄存器组(0x0800-0x08FF)
主设备优先级寄存器 (每个主设备32位)
typedef union {
struct {
uint32_t priority : 4; // [3:0] 优先级 (0-15)
uint32_t urgent_level : 4; // [7:4] 紧急级别
uint32_t timeout_val : 8; // [15:8] 超时值
uint32_t reserved : 12; // [27:16] 保留
uint32_t enable : 1; // [28] QoS使能
uint32_t lock : 1; // [29] 配置锁定
uint32_t bypass : 2; // [31:30] 旁路模式
} bits;
uint32_t value;} noc_qos_priority_t;
具体寄存器偏移
|----------------|----------------|------------|-------------|
| 偏移 | 主设备 | 描述 | 建议值 |
| 0x0800 | CPU0 | CPU0读优先级 | 0xF (最高) |
| 0x0804 | CPU1 | CPU1读优先级 | 0xF |
| 0x0808 | CPU2 | CPU2读优先级 | 0xF |
| 0x080C | CPU3 | CPU3读优先级 | 0xF |
| 0x0810 | GPU | GPU读/写优先级 | 0x8-0xC |
| 0x0814 | VCODEC | 视频编解码器优先级 | 0x8-0xA |
| 0x0818 | VOP | 显示控制器优先级 | 0xA-0xD |
| 0x081C | ISP | 图像处理器优先级 | 0x6-0x8 |
| 0x0820 | EDP | eDP接口优先级 | 0x7-0x9 |
| 0x0824 | HDMI | HDMI接口优先级 | 0x7-0x9 |
| 0x0828 | USB | USB控制器优先级 | 0x5-0x7 |
| 0x082C | SDMMC | SD/MMC卡优先级 | 0x4-0x6 |
| 0x0830 | GMAC | 以太网优先级 | 0x5-0x7 |
举例说明

2,带宽控制寄存器组(0x0900-0x09FF)
带宽限制寄存器格式
typedef union {
struct {
uint32_t bandwidth_limit : 10; // [9:0] 带宽限制值 (单位: 16MB/s)
uint32_t burst_limit : 6; // [15:10] 突发限制
uint32_t reserved1 : 8; // [23:16] 保留
uint32_t window_size : 4; // [27:24] 监控窗口大小
uint32_t reserved2 : 3; // [30:28] 保留
uint32_t enable : 1; // [31] 使能位
} bits;
uint32_t value;} noc_bandwidth_ctrl_t;
带宽分配寄存器
|----------------|-------------------------|--------------|
| 偏移 | 寄存器名称 | 功能描述 |
| 0x0900 | BW_LIMIT_CPU | CPU带宽限制 |
| 0x0904 | BW_LIMIT_GPU | GPU带宽限制 |
| 0x0908 | BW_LIMIT_VCODEC | 视频编解码器带宽 |
| 0x090C | BW_LIMIT_VOP | 显示控制器带宽 |
| 0x0910 | BW_LIMIT_ISP | ISP带宽限制 |
| 0x0914 | BW_LIMIT_USB | USB带宽限制 |
| 0x0918 | BW_LIMIT_SDMMC | SD/MMC带宽限制 |
| 0x091C | BW_LIMIT_DDR | DDR访问总带宽限制 |
计算示例 :
// 设置GPU带宽为800MB/s
// 800MB/s ÷ 16MB/s/单位 = 50 (0x32)
uint32_t gpu_bw = (50 & 0x3FF) | (1 << 31); // 使能带宽限制
writel(gpu_bw, NOC_BASE + 0x0904);
3,性能计数器寄存器组(0x0A00-0x0AFF)
性能监控寄存器
|----------------|---------------------|--------------|
| 偏移 | 寄存器名称 | 功能描述 |
| 0x0A00 | PERF_CTRL | 性能计数器控制 |
| 0x0A04 | PERF_EVENT_SEL | 事件选择 |
| 0x0A08 | PERF_COUNT0 | 计数器0值 |
| 0x0A0C | PERF_COUNT1 | 计数器1值 |
| 0x0A10 | PERF_COUNT2 | 计数器2值 |
| 0x0A14 | PERF_COUNT3 | 计数器3值 |
| 0x0A18 | PERF_LATENCY_MIN | 最小延迟 |
| 0x0A1C | PERF_LATENCY_MAX | 最大延迟 |
| 0x0A20 | PERF_LATENCY_AVG | 平均延迟 |
性能计数器控制寄存器 :
// PERF_CTRL (0x0A00)
#define PERF_ENABLE (1 << 0) // 使能所有计数器
#define PERF_RESET (1 << 1) // 复位所有计数器
#define PERF_INTERRUPT_EN (1 << 2) // 中断使能
#define PERF_WINDOW_MASK 0xFFFF0000 // 监控窗口掩码
// 支持监控的事件类型
enum noc_perf_event {
PERF_EVENT_READ_BYTES = 0x01, // 读取字节数
PERF_EVENT_WRITE_BYTES = 0x02, // 写入字节数
PERF_EVENT_READ_OPS = 0x03, // 读操作次数
PERF_EVENT_WRITE_OPS = 0x04, // 写操作次数
PERF_EVENT_LATENCY = 0x05, // 延迟
PERF_EVENT_CONGESTION = 0x06, // 拥塞周期
PERF_EVENT_TIMEOUT = 0x07, // 超时次数 };
4,仲裁控制寄存器组(0x0B00-0x0BFF)
|----------------|-------------------|--------------|
| 偏移 | 寄存器名称 | 功能描述 |
| 0x0B00 | ARB_CTRL | 仲裁器控制 |
| 0x0B04 | ARB_WEIGHT_CPU | CPU权重设置 |
| 0x0B08 | ARB_WEIGHT_GPU | GPU权重设置 |
| 0x0B0C | ARB_WEIGHT_VCODEC | 视频编解码器权重 |
| 0x0B10 | ARB_WEIGHT_VOP | 显示控制器权重 |
| 0x0B14 | ARB_ALGORITHM | 仲裁算法选择 |
仲裁算法配置 :
// ARB_CTRL (0x0B00)
#define ARB_ENABLE (1 << 0) // 仲裁器使能
#define ARB_MODE_MASK (3 << 1) // 仲裁模式
#define ARB_MODE_FIXED (0 << 1) // 固定优先级
#define ARB_MODE_ROUND_ROBIN (1 << 1) // 轮询
#define ARB_MODE_WEIGHTED (2 << 1) // 权重轮询
#define ARB_MODE_ADAPTIVE (3 << 1) // 自适应
#define ARB_LOCK (1 << 3) // 配置锁定
权重寄存器格式 :
typedef union {
struct {
uint32_t read_weight : 8; // [7:0] 读操作权重
uint32_t write_weight : 8; // [15:8] 写操作权重
uint32_t reserved : 16; // [31:16] 保留
} bits;
uint32_t value;} noc_arb_weight_t;
4,状态和错误寄存器组(0x0C00-0x0CFF)
|----------------|-------------------|--------------|
| 偏移 | 寄存器名称 | 功能描述 |
| 0x0C00 | STATUS | 总体状态 |
| 0x0C04 | ERROR_STATUS | 错误状态 |
| 0x0C08 | TIMEOUT_COUNTER | 超时计数器 |
| 0x0C0C | CONGESTION_STATUS | 拥塞状态 |
| 0x0C10 | BUS_UTILIZATION | 总线利用率 |
| 0x0C14 | SLICE_ACTIVE | 激活的主设备 |
| 0x0C18 | LATENCY_STATUS | 当前延迟 |
| 0x0C1C | DEBUG_INFO | 调试信息 |
状态寄存器位定义 :
// STATUS (0x0C00)
#define STAT_BUS_BUSY (1 << 0) // 总线忙
#define STAT_CONGESTED (1 << 1) // 总线拥塞
#define STAT_TIMEOUT_OCCUR (1 << 2) // 发生超时
#define STAT_ERROR_OCCUR (1 << 3) // 发生错误
#define STAT_QOS_ACTIVE (1 << 4) // QoS激活
#define STAT_ARB_ACTIVE (1 << 5) // 仲裁器激活
#define STAT_PERF_ACTIVE (1 << 6) // 性能监控激活
错误状态寄存器 :
// ERROR_STATUS (0x0C04)
#define ERR_ILLEGAL_ADDR (1 << 0) // 非法地址访问
#define ERR_SECURITY_VIOL (1 << 1) // 安全违规
#define ERR_PROTOCOL (1 << 2) // 协议错误
#define ERR_DATA_PARITY (1 << 3) // 数据奇偶校验错
#define ERR_ADDR_PARITY (1 << 4) // 地址奇偶校验错
#define ERR_TIMEOUT (1 << 5) // 访问超时
#define ERR_SLAVE_BUSY (1 << 6) // 从设备忙
#define ERR_MASTER_ABORT (1 << 7) // 主设备中止
举例说明:

三,典型使用场景
1 .U-Boot初始化配置
void rk3288_noc_init(void){
volatile uint32_t *noc_base = (uint32_t *)0xFFAC0000;
/* 1. 设置CPU最高优先级 */
noc_base[0x0800/4] = 0xF000000F; // CPU0
noc_base[0x0804/4] = 0xF000000F; // CPU1
noc_base[0x0808/4] = 0xF000000F; // CPU2
noc_base[0x080C/4] = 0xF000000F; // CPU3
/* 2. 设置GPU优先级和带宽 */
// 优先级: 0xB, 带宽: 400MB/s
noc_base[0x0810/4] = 0xB000000B; // GPU优先级
noc_base[0x0904/4] = (25 << 0) | (1 << 31); // 带宽限制
/* 3. 设置视频编解码器 */
noc_base[0x0814/4] = 0xA000000A; // VCODEC优先级
noc_base[0x0908/4] = (50 << 0) | (1 << 31); // 800MB/s
/* 4. 设置显示控制器 */
noc_base[0x0818/4] = 0xC000000C; // VOP优先级
noc_base[0x090C/4] = (63 << 0) | (1 << 31); // 1GB/s
/* 5. 配置仲裁器 */
noc_base[0x0B00/4] = ARB_ENABLE | ARB_MODE_WEIGHTED;
noc_base[0x0B04/4] = 0x20202020; // CPU权重
noc_base[0x0B08/4] = 0x10101010; // GPU权重
/* 6. 总带宽限制 */
noc_base[0x091C/4] = (400 << 0) | (1 << 31); // 6.4GB/s总限
/* 7. 启用性能监控 */
noc_base[0x0A00/4] = PERF_ENABLE | (0x1000 << 16); // 窗口大小 }
2. 多媒体场景优化
void setup_noc_for_4k_video_playback(void){
uint32_t *noc = (uint32_t *)0xFFAC0000;
/* 视频播放时GPU和VCODEC需要高带宽 */
// GPU: 优先级12,带宽600MB/s
noc[0x0810/4] = 0xC000000C;
noc[0x0904/4] = (37 << 0) | (1 << 31);
// VCODEC: 优先级13,带宽800MB/s
noc[0x0814/4] = 0xD000000D;
noc[0x0908/4] = (50 << 0) | (1 << 31);
// VOP: 优先级14,带宽400MB/s
noc[0x0818/4] = 0xE000000E;
noc[0x090C/4] = (25 << 0) | (1 << 31);
// 降低其他设备优先级
noc[0x0820/4] = 0x50000005; // USB降为5
noc[0x0824/4] = 0x40000004; // SDMMC降为4 }
3,寄存器操作封装函数
void noc_set_priority(uint32_t master_id, uint32_t priority) {
uint32_t reg = 0x0800 + (master_id * 4);
uint32_t val = (priority & 0xF) | (0xF0000000) | (1 << 28);
writel(val, NOC_BASE + reg);}
void noc_set_bandwidth(uint32_t master_id, uint32_t mbps) {
uint32_t reg = 0x0900 + (master_id * 4);
uint32_t val = ((mbps / 16) & 0x3FF) | (1 << 31);
writel(val, NOC_BASE + reg);}
uint32_t noc_get_utilization(void) {
return readl(NOC_BASE + 0x0C10) & 0xFF;}
四,调试和诊断
1.读取总线状态
uint32_t get_noc_status(void){
uint32_t *noc = (uint32_t *)0xFFAC0000;
uint32_t status = noc[0x0C00/4];
uint32_t errors = noc[0x0C04/4];
uint32_t utilization = noc[0x0C10/4];
printf("NOC Status: 0x%08X\n", status);
printf("Errors: 0x%08X\n", errors);
printf("Utilization: %d%%\n", (utilization & 0xFF));
return status;}
2.性能监控
void monitor_noc_performance(void){
uint32_t *noc = (uint32_t *)0xFFAC0000;
// 选择监控事件:读取字节数
noc[0x0A04/4] = PERF_EVENT_READ_BYTES;
// 启动监控
noc[0x0A00/4] = PERF_ENABLE;
// 延时一段时间
udelay(1000000); // 1秒
// 读取计数器值
uint32_t read_bytes = noc[0x0A08/4];
printf("Read bandwidth: %u MB/s\n", read_bytes / (1024*1024));}
五,注意事项
配置顺序 :先配置优先级,再配置带宽,最后启用仲裁器
时钟要求 :NOC模块需要PCLK和ACLK时钟
复位影响 :软复位不会清除NOC寄存器,需要手动复位
性能影响 :不正确的QoS配置可能导致系统性能下降
安全限制 :某些安全区域配置需要TrustZone权限