mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-24 07:33:02 +00:00
421dfa4252
t8103 and t600x use "asc-dram-mask" in iop-dcp-nub to mask bits out of
DMA addresses. This needs to be used in the firmware mappings
check/remap since the segments have maskable bits sets.
Fixes: 8332e24
("dcp: Undo carnage from bad stage1 DART code")
Signed-off-by: Janne Grunau <j@jannau.net>
273 lines
7.3 KiB
C
273 lines
7.3 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
|
|
#include "../config.h"
|
|
|
|
#include "adt.h"
|
|
#include "afk.h"
|
|
#include "dcp.h"
|
|
#include "firmware.h"
|
|
#include "malloc.h"
|
|
#include "pmgr.h"
|
|
#include "rtkit.h"
|
|
#include "smc.h"
|
|
#include "string.h"
|
|
#include "utils.h"
|
|
|
|
#include "dcp/dptx_phy.h"
|
|
|
|
struct adt_function_smc_gpio {
|
|
u32 phandle;
|
|
char four_cc[4];
|
|
u32 gpio;
|
|
u32 unk;
|
|
};
|
|
|
|
static char dcp_pmgr_dev[16] = "DISP0_CPU0";
|
|
static u32 dcp_die;
|
|
|
|
static int dcp_hdmi_dptx_init(dcp_dev_t *dcp, const display_config_t *cfg)
|
|
{
|
|
int node = adt_path_offset(adt, cfg->dp2hdmi_gpio);
|
|
if (node < 0) {
|
|
printf("dcp: failed to find dp2hdmi-gpio node '%s'\n", cfg->dp2hdmi_gpio);
|
|
return -1;
|
|
}
|
|
struct adt_function_smc_gpio dp2hdmi_pwr, hdmi_pwr;
|
|
|
|
int err =
|
|
adt_getprop_copy(adt, node, "function-dp2hdmi_pwr_en", &dp2hdmi_pwr, sizeof(dp2hdmi_pwr));
|
|
if (err < 0)
|
|
printf("dcp: failed to get dp2hdmi_pwr_en gpio\n");
|
|
else
|
|
dcp->dp2hdmi_pwr_gpio = dp2hdmi_pwr.gpio;
|
|
err = adt_getprop_copy(adt, node, "function-hdmi_pwr_en", &hdmi_pwr, sizeof(hdmi_pwr));
|
|
if (err < 0)
|
|
printf("dcp: failed to get hdmi_pwr_en gpio\n");
|
|
else
|
|
dcp->hdmi_pwr_gpio = hdmi_pwr.gpio;
|
|
|
|
if (dcp->dp2hdmi_pwr_gpio && dcp->hdmi_pwr_gpio) {
|
|
smc_dev_t *smc = smc_init();
|
|
if (smc) {
|
|
smc_write_u32(smc, dcp->dp2hdmi_pwr_gpio, 0x800001);
|
|
smc_write_u32(smc, dcp->hdmi_pwr_gpio, 0x800001);
|
|
smc_shutdown(smc);
|
|
}
|
|
}
|
|
|
|
dcp->die = cfg->die;
|
|
|
|
dcp->phy = dptx_phy_init(cfg->dptx_phy, cfg->dcp_index);
|
|
if (!dcp->phy) {
|
|
printf("dcp: failed to init (lp)dptx-phy '%s'\n", cfg->dptx_phy);
|
|
return -1;
|
|
}
|
|
|
|
dcp->dpav_ep = dcp_dpav_init(dcp);
|
|
if (!dcp->dpav_ep) {
|
|
printf("dcp: failed to initialize dpav endpoint\n");
|
|
return -1;
|
|
}
|
|
|
|
dcp->dptx_ep = dcp_dptx_init(dcp, cfg->num_dptxports);
|
|
if (!dcp->dptx_ep) {
|
|
printf("dcp: failed to initialize dptx-port endpoint\n");
|
|
dcp_dpav_shutdown(dcp->dpav_ep);
|
|
return -1;
|
|
}
|
|
|
|
#ifdef RTKIT_SYSLOG
|
|
// start system endpoint when extended logging is requested
|
|
dcp->system_ep = dcp_system_init(dcp);
|
|
if (!dcp->system_ep) {
|
|
printf("dcp: failed to initialize system endpoint\n");
|
|
dcp_dptx_shutdown(dcp->dptx_ep);
|
|
dcp_dpav_shutdown(dcp->dpav_ep);
|
|
return -1;
|
|
}
|
|
|
|
dcp_system_set_property_u64(dcp->system_ep, "gAFKConfigLogMask", 0xffff);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dcp_connect_dptx(dcp_dev_t *dcp)
|
|
{
|
|
if (dcp->dptx_ep && dcp->phy) {
|
|
return dcp_dptx_connect(dcp->dptx_ep, dcp->phy, dcp->die, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dcp_work(dcp_dev_t *dcp)
|
|
{
|
|
return afk_epic_work(dcp->afk, -1);
|
|
}
|
|
|
|
static int dcp_create_firmware_mappings(const display_config_t *cfg, dcp_dev_t *dcp)
|
|
{
|
|
int created = 0;
|
|
int dcp_node = adt_path_offset(adt, cfg->dcp);
|
|
int node = adt_first_child_offset(adt, dcp_node);
|
|
if (node < 0) {
|
|
printf("dcp: iop-dcp*-nub not found!\n");
|
|
return -1;
|
|
}
|
|
|
|
u64 asc_dram_mask;
|
|
if (ADT_GETPROP(adt, node, "asc-dram-mask", &asc_dram_mask) < 0)
|
|
asc_dram_mask = 0;
|
|
|
|
const struct adt_segment_ranges *seg;
|
|
u32 segments_len;
|
|
|
|
seg = adt_getprop(adt, node, "segment-ranges", &segments_len);
|
|
unsigned int count = segments_len / sizeof(*seg);
|
|
|
|
for (unsigned int i = 0; i < count; i++) {
|
|
u64 iova = seg[i].remap & ~asc_dram_mask;
|
|
if (dart_translate_silent(dcp->dart_dcp, iova))
|
|
continue;
|
|
|
|
size_t len = ALIGN_UP(seg[i].size, SZ_16K);
|
|
u32 flags = i == 0 ? 0b0100 : 0; // TEXT gets this bit set?
|
|
printf("dcp: Mapping segment #%u %lx -> %lx [%lx]\n", i, iova, seg[i].phys, len);
|
|
if (dart_map_flags(dcp->dart_dcp, iova, (void *)seg[i].phys, len, flags)) {
|
|
printf("dcp: Failed to map segment\n");
|
|
return -1;
|
|
}
|
|
created++;
|
|
}
|
|
|
|
return created;
|
|
}
|
|
|
|
dcp_dev_t *dcp_init(const display_config_t *cfg)
|
|
{
|
|
u32 sid;
|
|
|
|
if (cfg && cfg->dptx_phy[0]) {
|
|
if (os_firmware.version != V13_5) {
|
|
printf("dcp: dtpx-port is only supported with V13_5 OS firmware.\n");
|
|
return NULL;
|
|
}
|
|
|
|
strncpy(dcp_pmgr_dev, cfg->pmgr_dev, sizeof(dcp_pmgr_dev));
|
|
dcp_die = cfg->die;
|
|
pmgr_adt_power_enable(cfg->dcp);
|
|
pmgr_adt_power_enable(cfg->dptx_phy);
|
|
mdelay(25);
|
|
}
|
|
|
|
int dart_node = adt_path_offset(adt, cfg->dcp_dart);
|
|
int node = adt_first_child_offset(adt, dart_node);
|
|
if (node < 0) {
|
|
printf("dcp: mapper-dcp* not found!\n");
|
|
return NULL;
|
|
}
|
|
if (ADT_GETPROP(adt, node, "reg", &sid) < 0) {
|
|
printf("dcp: failed to read dart stream ID!\n");
|
|
return NULL;
|
|
}
|
|
|
|
dcp_dev_t *dcp = calloc(1, sizeof(dcp_dev_t));
|
|
if (!dcp)
|
|
return NULL;
|
|
|
|
dcp->dart_dcp = dart_init_adt(cfg->dcp_dart, 0, sid, true);
|
|
if (!dcp->dart_dcp) {
|
|
printf("dcp: failed to initialize DCP DART\n");
|
|
goto out_free;
|
|
}
|
|
u64 vm_base = dart_vm_base(dcp->dart_dcp);
|
|
dart_setup_pt_region(dcp->dart_dcp, cfg->dcp_dart, sid, vm_base);
|
|
|
|
dcp->dart_disp = dart_init_adt(cfg->disp_dart, 0, 0, true);
|
|
if (!dcp->dart_disp) {
|
|
printf("dcp: failed to initialize DISP DART\n");
|
|
goto out_dart_dcp;
|
|
}
|
|
// set disp0's page tables at dart-dcp's vm-base
|
|
dart_setup_pt_region(dcp->dart_disp, cfg->disp_dart, 0, vm_base);
|
|
|
|
dcp->iovad_dcp = iovad_init(vm_base + 0x10000000, vm_base + 0x20000000);
|
|
|
|
int ret = dcp_create_firmware_mappings(cfg, dcp);
|
|
if (ret < 0) {
|
|
printf("dcp: failed to create firmware mappings\n");
|
|
goto out_iovad;
|
|
}
|
|
if (ret > 0) {
|
|
pmgr_reset(dcp_die, dcp_pmgr_dev);
|
|
}
|
|
|
|
dcp->asc = asc_init(cfg->dcp);
|
|
if (!dcp->asc) {
|
|
printf("dcp: failed to initialize ASC\n");
|
|
goto out_iovad;
|
|
}
|
|
|
|
dcp->rtkit = rtkit_init("dcp", dcp->asc, dcp->dart_dcp, dcp->iovad_dcp, NULL, false);
|
|
if (!dcp->rtkit) {
|
|
printf("dcp: failed to initialize RTKit\n");
|
|
goto out_iovad;
|
|
}
|
|
|
|
if (!rtkit_boot(dcp->rtkit)) {
|
|
printf("dcp: failed to boot RTKit\n");
|
|
goto out_iovad;
|
|
}
|
|
|
|
dcp->afk = afk_epic_init(dcp->rtkit);
|
|
if (!dcp->afk) {
|
|
printf("dcp: failed to initialize AFK\n");
|
|
goto out_rtkit;
|
|
}
|
|
|
|
if (cfg && cfg->dptx_phy[0]) {
|
|
int ret = dcp_hdmi_dptx_init(dcp, cfg);
|
|
if (ret < 0)
|
|
goto out_afk;
|
|
}
|
|
|
|
return dcp;
|
|
|
|
out_afk:
|
|
afk_epic_shutdown(dcp->afk);
|
|
out_rtkit:
|
|
rtkit_quiesce(dcp->rtkit);
|
|
rtkit_free(dcp->rtkit);
|
|
out_iovad:
|
|
iovad_shutdown(dcp->iovad_dcp, dcp->dart_dcp);
|
|
dart_shutdown(dcp->dart_disp);
|
|
out_dart_dcp:
|
|
dart_shutdown(dcp->dart_dcp);
|
|
out_free:
|
|
free(dcp);
|
|
return NULL;
|
|
}
|
|
|
|
int dcp_shutdown(dcp_dev_t *dcp, bool sleep)
|
|
{
|
|
/* dcp/dcp0 on desktop M2 and M2 Pro/Max devices do not wake from sleep */
|
|
dcp_system_shutdown(dcp->system_ep);
|
|
dcp_dptx_shutdown(dcp->dptx_ep);
|
|
dcp_dpav_shutdown(dcp->dpav_ep);
|
|
free(dcp->phy);
|
|
afk_epic_shutdown(dcp->afk);
|
|
if (sleep) {
|
|
rtkit_sleep(dcp->rtkit);
|
|
pmgr_reset(dcp_die, dcp_pmgr_dev);
|
|
} else {
|
|
rtkit_quiesce(dcp->rtkit);
|
|
}
|
|
rtkit_free(dcp->rtkit);
|
|
dart_shutdown(dcp->dart_disp);
|
|
iovad_shutdown(dcp->iovad_dcp, dcp->dart_dcp);
|
|
dart_shutdown(dcp->dart_dcp);
|
|
free(dcp);
|
|
|
|
return 0;
|
|
}
|