amdgpu: fix ASIC detection, quirk stubs, firmware store, connector descriptors, register offsets
- Fix ASIC detection: use PCI device_id instead of broken MMIO offset-0 read. Add proper device_id->ASIC family lookup table covering Navi10-Navi33 (RDNA1/RDNA2/RDNA3). Add per-family properties (DCN revision, firmware name, OTG/HUBP base offsets, HPD register). - Wire quirk flags from Rust to C: replace pci_get_quirk_flags/pci_has_quirk stubs (previously always returned 0/false) with stored quirk_flags set via new FFI redox_pci_set_quirk_flags(). Quirk-aware IRQ policy now actually works. - Store firmware blobs from Rust to C: add redox_firmware_store() FFI to pass firmware blobs from AmdDriver.firmware HashMap into C-side storage. C side can now fall back to scheme:firmware if blobs not pre-stored. - Fix connector descriptors: replace hardcoded 600x340mm fake dimensions with per-ASIC-family connector tables (desktop dGPU vs APU layout). Set mm_width/ mm_height to 0 (unprobed — needs DC hardware detection). HPD register offset now comes from per-family asic_props table. - Fix register offsets: replace hardcoded OTG base 0x4800 / HUBP base 0x5800 (Navi23-specific) with per-DCN-revision dispatch from asic_props table (DCN2.0=0x4000/0x5000, DCN3.0=0x4800/0x5800, DCN3.2=0x5000/0x6000).
This commit is contained in:
@@ -10,19 +10,143 @@ static u64 g_fb_phys;
|
||||
static size_t g_fb_size;
|
||||
static int g_asic_family = -1;
|
||||
|
||||
/* ASIC family definitions based on device IDs */
|
||||
#define ASIC_FAMILY_NAVI10 0x7310
|
||||
#define ASIC_FAMILY_NAVI14 0x7340
|
||||
#define ASIC_FAMILY_NAVI21 0x73A0
|
||||
#define ASIC_FAMILY_NAVI22 0x73C0
|
||||
#define ASIC_FAMILY_NAVI23 0x73E0
|
||||
#define ASIC_FAMILY_NAVI24 0x7420
|
||||
#define ASIC_FAMILY_NAVI31 0x7440
|
||||
#define ASIC_FAMILY_NAVI32 0x7480
|
||||
#define ASIC_FAMILY_NAVI33 0x74A0
|
||||
enum {
|
||||
ASIC_NAVI10 = 1,
|
||||
ASIC_NAVI14,
|
||||
ASIC_NAVI12,
|
||||
ASIC_NAVI21,
|
||||
ASIC_NAVI22,
|
||||
ASIC_NAVI23,
|
||||
ASIC_NAVI24,
|
||||
ASIC_NAVI31,
|
||||
ASIC_NAVI32,
|
||||
ASIC_NAVI33,
|
||||
ASIC_MAX,
|
||||
};
|
||||
|
||||
struct asic_props {
|
||||
int family;
|
||||
const char *name;
|
||||
const char *dmcub_firmware;
|
||||
u32 otg_base[4];
|
||||
u32 hubp_base[4];
|
||||
u32 hpd_status_reg;
|
||||
int max_connectors;
|
||||
int max_crtcs;
|
||||
};
|
||||
|
||||
static const struct asic_props g_asic_table[] = {
|
||||
[ASIC_NAVI10] = {
|
||||
.family = ASIC_NAVI10, .name = "Navi10 (RDNA1)",
|
||||
.dmcub_firmware = "dmcub_dcn20.bin",
|
||||
.otg_base = {0x4000, 0x4800, 0x5000, 0x5800},
|
||||
.hubp_base = {0x5000, 0x5400, 0x5800, 0x5c00},
|
||||
.hpd_status_reg = 0x1e74, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI14] = {
|
||||
.family = ASIC_NAVI14, .name = "Navi14 (RDNA1)",
|
||||
.dmcub_firmware = "dmcub_dcn20.bin",
|
||||
.otg_base = {0x4000, 0x4800, 0x5000, 0x5800},
|
||||
.hubp_base = {0x5000, 0x5400, 0x5800, 0x5c00},
|
||||
.hpd_status_reg = 0x1e74, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI12] = {
|
||||
.family = ASIC_NAVI12, .name = "Navi12 (RDNA1)",
|
||||
.dmcub_firmware = "dmcub_dcn20.bin",
|
||||
.otg_base = {0x4000, 0x4800, 0x5000, 0x5800},
|
||||
.hubp_base = {0x5000, 0x5400, 0x5800, 0x5c00},
|
||||
.hpd_status_reg = 0x1e74, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI21] = {
|
||||
.family = ASIC_NAVI21, .name = "Navi21 / Sienna Cichlid (RDNA2)",
|
||||
.dmcub_firmware = "dmcub_dcn31.bin",
|
||||
.otg_base = {0x4800, 0x5000, 0x5800, 0x6000},
|
||||
.hubp_base = {0x5800, 0x5c00, 0x6000, 0x6400},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI22] = {
|
||||
.family = ASIC_NAVI22, .name = "Navi22 / Navy Flounder (RDNA2)",
|
||||
.dmcub_firmware = "dmcub_dcn31.bin",
|
||||
.otg_base = {0x4800, 0x5000, 0x5800, 0x6000},
|
||||
.hubp_base = {0x5800, 0x5c00, 0x6000, 0x6400},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI23] = {
|
||||
.family = ASIC_NAVI23, .name = "Navi23 / Dimgrey Cavefish (RDNA2)",
|
||||
.dmcub_firmware = "dmcub_dcn31.bin",
|
||||
.otg_base = {0x4800, 0x5000, 0x5800, 0x6000},
|
||||
.hubp_base = {0x5800, 0x5c00, 0x6000, 0x6400},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI24] = {
|
||||
.family = ASIC_NAVI24, .name = "Navi24 / Beige Goby (RDNA2)",
|
||||
.dmcub_firmware = "dmcub_dcn31.bin",
|
||||
.otg_base = {0x4800, 0x5000, 0x5800, 0x6000},
|
||||
.hubp_base = {0x5800, 0x5c00, 0x6000, 0x6400},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI31] = {
|
||||
.family = ASIC_NAVI31, .name = "Navi31 / Plum Bonito (RDNA3)",
|
||||
.dmcub_firmware = "dmcub_dcn32.bin",
|
||||
.otg_base = {0x5000, 0x5800, 0x6000, 0x6800},
|
||||
.hubp_base = {0x6000, 0x6400, 0x6800, 0x6c00},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI32] = {
|
||||
.family = ASIC_NAVI32, .name = "Navi32 / Wheat Nas (RDNA3)",
|
||||
.dmcub_firmware = "dmcub_dcn32.bin",
|
||||
.otg_base = {0x5000, 0x5800, 0x6000, 0x6800},
|
||||
.hubp_base = {0x6000, 0x6400, 0x6800, 0x6c00},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
[ASIC_NAVI33] = {
|
||||
.family = ASIC_NAVI33, .name = "Navi33 / Hotpink Bonefish (RDNA3)",
|
||||
.dmcub_firmware = "dmcub_dcn32.bin",
|
||||
.otg_base = {0x5000, 0x5800, 0x6000, 0x6800},
|
||||
.hubp_base = {0x6000, 0x6400, 0x6800, 0x6c00},
|
||||
.hpd_status_reg = 0x4A00, .max_connectors = 4, .max_crtcs = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static int asic_from_device_id(u16 device_id)
|
||||
{
|
||||
switch (device_id & 0xFFF0) {
|
||||
case 0x7310: return ASIC_NAVI10;
|
||||
case 0x7340: return ASIC_NAVI14;
|
||||
case 0x7360: return ASIC_NAVI12;
|
||||
case 0x73A0: return ASIC_NAVI21;
|
||||
case 0x73C0: return ASIC_NAVI22;
|
||||
case 0x73E0: return ASIC_NAVI23;
|
||||
case 0x7420: return ASIC_NAVI24;
|
||||
case 0x7440: return ASIC_NAVI31;
|
||||
case 0x7480: return ASIC_NAVI32;
|
||||
case 0x74A0: return ASIC_NAVI33;
|
||||
default: break;
|
||||
}
|
||||
|
||||
/* Wider ranges for variant device IDs within each family */
|
||||
if (device_id >= 0x7300 && device_id < 0x7320) return ASIC_NAVI10;
|
||||
if (device_id >= 0x7340 && device_id < 0x7360) return ASIC_NAVI14;
|
||||
if (device_id >= 0x7360 && device_id < 0x7380) return ASIC_NAVI12;
|
||||
if (device_id >= 0x73A0 && device_id < 0x73C0) return ASIC_NAVI21;
|
||||
if (device_id >= 0x73C0 && device_id < 0x73E0) return ASIC_NAVI22;
|
||||
if (device_id >= 0x73E0 && device_id < 0x7400) return ASIC_NAVI23;
|
||||
if (device_id >= 0x7420 && device_id < 0x7440) return ASIC_NAVI24;
|
||||
if (device_id >= 0x7440 && device_id < 0x7480) return ASIC_NAVI31;
|
||||
if (device_id >= 0x7480 && device_id < 0x74A0) return ASIC_NAVI32;
|
||||
if (device_id >= 0x74A0 && device_id < 0x74C0) return ASIC_NAVI33;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const struct asic_props *asic_props(void)
|
||||
{
|
||||
if (g_asic_family > 0 && g_asic_family < ASIC_MAX) {
|
||||
return &g_asic_table[g_asic_family];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define AMDGPU_DC_HPD_STATUS_REG 0x4A00
|
||||
#define AMDGPU_DC_MAX_CONNECTORS 4
|
||||
#define AMDGPU_DC_BYTES_PER_PIXEL 4U
|
||||
#define AMDGPU_DC_PIXEL_FORMAT_ARGB8888 3U
|
||||
|
||||
@@ -63,11 +187,24 @@ struct amdgpu_redox_connector_desc {
|
||||
int mm_height;
|
||||
};
|
||||
|
||||
static const struct amdgpu_redox_connector_desc g_connector_descs[AMDGPU_DC_MAX_CONNECTORS] = {
|
||||
{ .id = 1, .hpd_mask = 0x01, .connector_type = 10, .connector_type_id = 1, .encoder_id = 1, .mm_width = 600, .mm_height = 340 },
|
||||
{ .id = 2, .hpd_mask = 0x02, .connector_type = 10, .connector_type_id = 2, .encoder_id = 2, .mm_width = 600, .mm_height = 340 },
|
||||
{ .id = 3, .hpd_mask = 0x04, .connector_type = 11, .connector_type_id = 3, .encoder_id = 3, .mm_width = 600, .mm_height = 340 },
|
||||
{ .id = 4, .hpd_mask = 0x08, .connector_type = 11, .connector_type_id = 4, .encoder_id = 4, .mm_width = 600, .mm_height = 340 },
|
||||
static const struct amdgpu_redox_connector_desc g_connector_descs_desktop_dgpu[] = {
|
||||
{ .id = 1, .hpd_mask = 0x01, .connector_type = 10, .connector_type_id = 1,
|
||||
.encoder_id = 1, .mm_width = 0, .mm_height = 0 },
|
||||
{ .id = 2, .hpd_mask = 0x02, .connector_type = 10, .connector_type_id = 2,
|
||||
.encoder_id = 2, .mm_width = 0, .mm_height = 0 },
|
||||
{ .id = 3, .hpd_mask = 0x04, .connector_type = 10, .connector_type_id = 3,
|
||||
.encoder_id = 3, .mm_width = 0, .mm_height = 0 },
|
||||
{ .id = 4, .hpd_mask = 0x08, .connector_type = 11, .connector_type_id = 4,
|
||||
.encoder_id = 4, .mm_width = 0, .mm_height = 0 },
|
||||
};
|
||||
|
||||
static const struct amdgpu_redox_connector_desc g_connector_descs_apu[] = {
|
||||
{ .id = 1, .hpd_mask = 0x01, .connector_type = 11, .connector_type_id = 1,
|
||||
.encoder_id = 1, .mm_width = 0, .mm_height = 0 },
|
||||
{ .id = 2, .hpd_mask = 0x02, .connector_type = 10, .connector_type_id = 2,
|
||||
.encoder_id = 2, .mm_width = 0, .mm_height = 0 },
|
||||
{ .id = 3, .hpd_mask = 0x04, .connector_type = 14, .connector_type_id = 3,
|
||||
.encoder_id = 3, .mm_width = 0, .mm_height = 0 },
|
||||
};
|
||||
|
||||
static inline void __iomem *amdgpu_dc_reg_ptr(u32 base, u32 offset)
|
||||
@@ -110,10 +247,27 @@ static inline u32 amdgpu_dc_read_reg(u32 base, u32 offset)
|
||||
|
||||
static inline u32 amdgpu_dc_hpd_status(void)
|
||||
{
|
||||
if (amdgpu_dc_validate_mmio_access(0, AMDGPU_DC_HPD_STATUS_REG) != 0) {
|
||||
u32 hpd_reg;
|
||||
const struct asic_props *props = asic_props();
|
||||
|
||||
if (!props) {
|
||||
return 0;
|
||||
}
|
||||
return readl((u8 __iomem *)g_mmio_base + AMDGPU_DC_HPD_STATUS_REG);
|
||||
hpd_reg = props->hpd_status_reg;
|
||||
if (amdgpu_dc_validate_mmio_access(0, hpd_reg) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return readl((u8 __iomem *)g_mmio_base + hpd_reg);
|
||||
}
|
||||
|
||||
static const struct amdgpu_redox_connector_desc *connector_table(int *count)
|
||||
{
|
||||
if (g_asic_family == ASIC_NAVI14 || g_asic_family == ASIC_NAVI33) {
|
||||
*count = (int)ARRAY_SIZE(g_connector_descs_apu);
|
||||
return g_connector_descs_apu;
|
||||
}
|
||||
*count = (int)ARRAY_SIZE(g_connector_descs_desktop_dgpu);
|
||||
return g_connector_descs_desktop_dgpu;
|
||||
}
|
||||
|
||||
static void amdgpu_redox_log_irq_expectation(u64 quirk_flags)
|
||||
@@ -137,7 +291,7 @@ static void amdgpu_redox_log_irq_expectation(u64 quirk_flags)
|
||||
int amdgpu_dc_init(void *mmio_base, size_t mmio_size)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 gpu_id = 0;
|
||||
u16 device_id;
|
||||
const char *firmware_name = NULL;
|
||||
u64 quirk_flags = 0;
|
||||
|
||||
@@ -148,10 +302,18 @@ int amdgpu_dc_init(void *mmio_base, size_t mmio_size)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
gpu_id = readl(mmio_base);
|
||||
printk("amdgpu_redox: GPU ID = %#010x\n", gpu_id);
|
||||
if (!g_pci_dev) {
|
||||
pr_err("amdgpu_redox: no PCI device info; call redox_pci_set_device_info first\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (g_pci_dev) {
|
||||
device_id = g_pci_dev->device;
|
||||
printk("amdgpu_redox: PCI device_id = %#06x\n", device_id);
|
||||
|
||||
printk("amdgpu_redox: MMIO identity register = %#010x (not used for ASIC detection)\n",
|
||||
readl(mmio_base));
|
||||
|
||||
{
|
||||
quirk_flags = pci_get_quirk_flags(g_pci_dev);
|
||||
printk("amdgpu_redox: PCI %02x:%02x.%u quirk flags = %#llx\n",
|
||||
g_pci_dev->bus_number,
|
||||
@@ -173,51 +335,23 @@ int amdgpu_dc_init(void *mmio_base, size_t mmio_size)
|
||||
amdgpu_redox_log_irq_expectation(quirk_flags);
|
||||
}
|
||||
|
||||
switch (gpu_id) {
|
||||
case ASIC_FAMILY_NAVI10:
|
||||
g_asic_family = ASIC_FAMILY_NAVI10;
|
||||
firmware_name = "dmcub_dcn20.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI14:
|
||||
g_asic_family = ASIC_FAMILY_NAVI14;
|
||||
firmware_name = "dmcub_dcn20.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI21:
|
||||
g_asic_family = ASIC_FAMILY_NAVI21;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI22:
|
||||
g_asic_family = ASIC_FAMILY_NAVI22;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI23:
|
||||
g_asic_family = ASIC_FAMILY_NAVI23;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI24:
|
||||
g_asic_family = ASIC_FAMILY_NAVI24;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI31:
|
||||
g_asic_family = ASIC_FAMILY_NAVI31;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI32:
|
||||
g_asic_family = ASIC_FAMILY_NAVI32;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
case ASIC_FAMILY_NAVI33:
|
||||
g_asic_family = ASIC_FAMILY_NAVI33;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
default:
|
||||
pr_warn("amdgpu_redox: unknown ASIC %#010x, using DCN31 firmware\n", gpu_id);
|
||||
g_asic_family = gpu_id;
|
||||
firmware_name = "dmcub_dcn31.bin";
|
||||
break;
|
||||
g_asic_family = asic_from_device_id(device_id);
|
||||
if (g_asic_family < 0) {
|
||||
pr_err("amdgpu_redox: unknown AMD GPU device_id %#06x — cannot identify ASIC family\n",
|
||||
device_id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
printk("amdgpu_redox: ASIC family identified, loading firmware: %s\n", firmware_name);
|
||||
{
|
||||
const struct asic_props *props = asic_props();
|
||||
if (!props) {
|
||||
pr_err("amdgpu_redox: no properties for ASIC family %d\n", g_asic_family);
|
||||
return -ENODEV;
|
||||
}
|
||||
firmware_name = props->dmcub_firmware;
|
||||
printk("amdgpu_redox: identified %s, loading firmware: %s\n",
|
||||
props->name, firmware_name);
|
||||
}
|
||||
|
||||
{
|
||||
const struct firmware *fw = NULL;
|
||||
@@ -308,15 +442,18 @@ int amdgpu_dc_detect_connectors(void)
|
||||
|
||||
#ifdef __redox__
|
||||
u32 hpd_status = amdgpu_dc_hpd_status();
|
||||
int table_count;
|
||||
const struct amdgpu_redox_connector_desc *table = connector_table(&table_count);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMDGPU_DC_MAX_CONNECTORS; ++i) {
|
||||
if (hpd_status & g_connector_descs[i].hpd_mask) {
|
||||
for (i = 0; i < table_count; ++i) {
|
||||
if (hpd_status & table[i].hpd_mask) {
|
||||
num_connectors++;
|
||||
}
|
||||
}
|
||||
|
||||
printk("amdgpu_redox: detected %d connector(s)\n", num_connectors);
|
||||
printk("amdgpu_redox: detected %d connector(s) via HPD status %#010x\n",
|
||||
num_connectors, hpd_status);
|
||||
#else
|
||||
printk("amdgpu_redox: running on Linux, using AMD DC detection\n");
|
||||
#endif
|
||||
@@ -341,11 +478,13 @@ int amdgpu_dc_get_connector_info(int idx, void *info)
|
||||
#ifdef __redox__
|
||||
{
|
||||
u32 hpd_status = amdgpu_dc_hpd_status();
|
||||
int table_count;
|
||||
const struct amdgpu_redox_connector_desc *table = connector_table(&table_count);
|
||||
int active_index = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AMDGPU_DC_MAX_CONNECTORS; ++i) {
|
||||
const struct amdgpu_redox_connector_desc *desc = &g_connector_descs[i];
|
||||
for (i = 0; i < table_count; ++i) {
|
||||
const struct amdgpu_redox_connector_desc *desc = &table[i];
|
||||
|
||||
if (!(hpd_status & desc->hpd_mask)) {
|
||||
continue;
|
||||
@@ -425,10 +564,21 @@ int amdgpu_dc_set_crtc(int crtc_id, uint64_t fb_addr, uint32_t width, uint32_t h
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
u32 otg_base = 0x4800 + (crtc_id * 0x800);
|
||||
u32 hubp_base = 0x5800 + (crtc_id * 0x400);
|
||||
u32 otg_base;
|
||||
u32 hubp_base;
|
||||
u32 otg_control;
|
||||
|
||||
{
|
||||
const struct asic_props *props = asic_props();
|
||||
if (!props || crtc_id >= props->max_crtcs) {
|
||||
pr_err("amdgpu_redox: no register layout for ASIC family %d crtc %d\n",
|
||||
g_asic_family, crtc_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
otg_base = props->otg_base[crtc_id];
|
||||
hubp_base = props->hubp_base[crtc_id];
|
||||
}
|
||||
|
||||
if (amdgpu_dc_validate_mmio_access(otg_base, AMDGPU_DC_OTG_VSTARTUP) != 0 ||
|
||||
amdgpu_dc_validate_mmio_access(hubp_base, AMDGPU_DC_HUBP_FLIP_ADDR_HIGH) != 0) {
|
||||
return -EINVAL;
|
||||
|
||||
@@ -244,6 +244,7 @@ extern void redox_pci_set_device_info(u16 vendor, u16 device,
|
||||
u8 func_number, u8 revision, u32 irq,
|
||||
u64 bar0_addr, u64 bar0_size,
|
||||
u64 bar2_addr, u64 bar2_size);
|
||||
extern void redox_pci_set_quirk_flags(u64 quirk_flags);
|
||||
extern void redox_pci_dev_put(struct pci_dev *pdev);
|
||||
extern int redox_pci_enable_device(struct pci_dev *pdev);
|
||||
extern void redox_pci_set_master(struct pci_dev *pdev);
|
||||
@@ -288,9 +289,11 @@ struct firmware {
|
||||
|
||||
extern int redox_request_firmware(const struct firmware **fw, const char *name, void *dev);
|
||||
extern void redox_release_firmware(const struct firmware *fw);
|
||||
extern void redox_firmware_store(const char *name, const u8 *data, size_t size);
|
||||
|
||||
#define request_firmware(fw, name, dev) redox_request_firmware((fw), (name), (dev))
|
||||
#define release_firmware(fw) redox_release_firmware((fw))
|
||||
#define firmware_store(name, data, size) redox_firmware_store((name), (data), (size))
|
||||
|
||||
#define dev_get_drvdata(dev) ((dev)->driver_data)
|
||||
#define dev_set_drvdata(dev, data) ((dev)->driver_data = (data))
|
||||
|
||||
@@ -221,8 +221,20 @@ void redox_dma_free_coherent(size_t size, void *vaddr, dma_addr_t dma_handle)
|
||||
*/
|
||||
static struct pci_dev g_pci_dev;
|
||||
static int g_pci_dev_populated;
|
||||
static u64 g_pci_quirk_flags;
|
||||
|
||||
#define REDOX_MAX_FIRMWARE_BYTES (64U * 1024U * 1024U)
|
||||
#define REDOX_MAX_STORED_FIRMWARES 32
|
||||
|
||||
struct redox_stored_firmware {
|
||||
char name[128];
|
||||
u8 *data;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
static struct redox_stored_firmware g_stored_firmware[REDOX_MAX_STORED_FIRMWARES];
|
||||
static int g_stored_firmware_count;
|
||||
static pthread_mutex_t g_firmware_store_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void redox_pci_set_device_info(u16 vendor, u16 device,
|
||||
u8 bus_number, u8 dev_number,
|
||||
@@ -299,14 +311,75 @@ void redox_pci_release_regions(struct pci_dev *pdev)
|
||||
u64 pci_get_quirk_flags(struct pci_dev *pdev)
|
||||
{
|
||||
(void)pdev;
|
||||
return 0;
|
||||
return g_pci_quirk_flags;
|
||||
}
|
||||
|
||||
bool pci_has_quirk(struct pci_dev *pdev, u64 flag)
|
||||
{
|
||||
(void)pdev;
|
||||
(void)flag;
|
||||
return false;
|
||||
return (g_pci_quirk_flags & flag) != 0;
|
||||
}
|
||||
|
||||
void redox_pci_set_quirk_flags(u64 quirk_flags)
|
||||
{
|
||||
g_pci_quirk_flags = quirk_flags;
|
||||
printk("PCI quirk flags stored: %#llx\n", (unsigned long long)quirk_flags);
|
||||
}
|
||||
|
||||
void redox_firmware_store(const char *name, const u8 *data, size_t size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!name || !data || size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (size > REDOX_MAX_FIRMWARE_BYTES) {
|
||||
pr_err("firmware_store: blob %s too large (%zu bytes, max %u)\n",
|
||||
name, size, REDOX_MAX_FIRMWARE_BYTES);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_firmware_store_lock);
|
||||
|
||||
for (i = 0; i < g_stored_firmware_count; ++i) {
|
||||
if (strcmp(g_stored_firmware[i].name, name) == 0) {
|
||||
free(g_stored_firmware[i].data);
|
||||
g_stored_firmware[i].data = malloc(size);
|
||||
if (!g_stored_firmware[i].data) {
|
||||
g_stored_firmware[i].size = 0;
|
||||
pthread_mutex_unlock(&g_firmware_store_lock);
|
||||
return;
|
||||
}
|
||||
memcpy(g_stored_firmware[i].data, data, size);
|
||||
g_stored_firmware[i].size = size;
|
||||
pthread_mutex_unlock(&g_firmware_store_lock);
|
||||
printk("firmware_store: replaced %s (%zu bytes)\n", name, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_stored_firmware_count >= REDOX_MAX_STORED_FIRMWARES) {
|
||||
pr_err("firmware_store: store full (%d entries), cannot store %s\n",
|
||||
g_stored_firmware_count, name);
|
||||
pthread_mutex_unlock(&g_firmware_store_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
i = g_stored_firmware_count;
|
||||
strncpy(g_stored_firmware[i].name, name, sizeof(g_stored_firmware[i].name) - 1);
|
||||
g_stored_firmware[i].name[sizeof(g_stored_firmware[i].name) - 1] = '\0';
|
||||
g_stored_firmware[i].data = malloc(size);
|
||||
if (!g_stored_firmware[i].data) {
|
||||
g_stored_firmware[i].size = 0;
|
||||
pthread_mutex_unlock(&g_firmware_store_lock);
|
||||
return;
|
||||
}
|
||||
memcpy(g_stored_firmware[i].data, data, size);
|
||||
g_stored_firmware[i].size = size;
|
||||
g_stored_firmware_count++;
|
||||
pthread_mutex_unlock(&g_firmware_store_lock);
|
||||
printk("firmware_store: stored %s (%zu bytes)\n", name, size);
|
||||
}
|
||||
|
||||
int redox_request_firmware(const struct firmware **fw, const char *name, void *dev)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use log::{info, warn};
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
#[cfg(no_amdgpu_c)]
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@@ -54,6 +55,12 @@ unsafe extern "C" {
|
||||
bar2_addr: u64,
|
||||
bar2_size: u64,
|
||||
);
|
||||
|
||||
#[link_name = "redox_pci_set_quirk_flags"]
|
||||
fn ffi_redox_pci_set_quirk_flags(quirk_flags: u64);
|
||||
|
||||
#[link_name = "redox_firmware_store"]
|
||||
fn ffi_redox_firmware_store(name: *const libc::c_char, data: *const u8, size: usize);
|
||||
}
|
||||
|
||||
#[cfg(no_amdgpu_c)]
|
||||
@@ -117,6 +124,7 @@ pub fn set_pci_device_info(
|
||||
bar0_size: u64,
|
||||
bar2_addr: u64,
|
||||
bar2_size: u64,
|
||||
quirk_flags: u64,
|
||||
) {
|
||||
#[cfg(not(no_amdgpu_c))]
|
||||
unsafe {
|
||||
@@ -133,6 +141,7 @@ pub fn set_pci_device_info(
|
||||
bar2_addr,
|
||||
bar2_size,
|
||||
);
|
||||
ffi_redox_pci_set_quirk_flags(quirk_flags);
|
||||
}
|
||||
let _ = (
|
||||
vendor,
|
||||
@@ -146,9 +155,22 @@ pub fn set_pci_device_info(
|
||||
bar0_size,
|
||||
bar2_addr,
|
||||
bar2_size,
|
||||
quirk_flags,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn store_firmware_blobs(firmware: &std::collections::HashMap<String, Vec<u8>>) {
|
||||
#[cfg(not(no_amdgpu_c))]
|
||||
for (name, data) in firmware {
|
||||
if let Ok(c_name) = CString::new(name.as_str()) {
|
||||
unsafe {
|
||||
ffi_redox_firmware_store(c_name.as_ptr(), data.as_ptr(), data.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
let _ = firmware;
|
||||
}
|
||||
|
||||
#[cfg(not(no_amdgpu_c))]
|
||||
fn amdgpu_dc_init(mmio_base: *const u8, mmio_size: usize) -> i32 {
|
||||
unsafe { ffi_amdgpu_redox_init(mmio_base, mmio_size, 0, 0) }
|
||||
|
||||
@@ -92,6 +92,9 @@ impl AmdDriver {
|
||||
}
|
||||
};
|
||||
|
||||
let quirks = info.quirks();
|
||||
let quirk_flags: u64 = quirks.bits();
|
||||
|
||||
display::set_pci_device_info(
|
||||
info.vendor_id,
|
||||
info.device_id,
|
||||
@@ -104,8 +107,11 @@ impl AmdDriver {
|
||||
bar0.size,
|
||||
bar2.as_ref().map(|b| b.addr).unwrap_or(0),
|
||||
bar2.as_ref().map(|b| b.size).unwrap_or(0),
|
||||
quirk_flags,
|
||||
);
|
||||
|
||||
display::store_firmware_blobs(&firmware);
|
||||
|
||||
let irq_handle = Some(InterruptHandle::setup(&info, &mut device).map_err(|e| {
|
||||
DriverError::Io(format!(
|
||||
"failed to setup interrupt for {}: {e}",
|
||||
|
||||
Reference in New Issue
Block a user