Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions Documentation/devicetree/bindings/display/apple,dcp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ properties:
- apple,t6041-dcp
- apple,t8140-dcp
- apple,t8142-dcp
- apple,t6050-dcp
- const: apple,dcp
- items:
- enum:
- apple,t8103-dcpext
- apple,t8112-dcpext
- apple,t6000-dcpext
- apple,t6020-dcpext
- apple,t6050-dcpext
- const: apple,dcpext
- items:
- const: apple,t8140-dcpext
Expand Down Expand Up @@ -76,13 +78,32 @@ properties:

clocks:
minItems: 1
maxItems: 2
maxItems: 64

clock-names:
minItems: 1
items:
- const: clock-154
- const: clock-194
maxItems: 64

apple,clock-ids:
oneOf:
- type: boolean
- $ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
maxItems: 64
description: |
Ordered firmware provider clock identifiers. Callback clock indices
select the corresponding entry in clocks. An explicitly empty table
is allowed when the provider has no clocks.

apple,firmware-physical-regs:
$ref: /schemas/types.yaml#/definitions/uint64-array
minItems: 1
maxItems: 10
description: |
Coprocessor physical base addresses in display register-table order,
including the bandwidth scratch and optional doorbell windows.
The number of entries must match the complete register table.
Omit on identity-mapped systems; reg supplies the physical view.

memory-region:
minItems: 1
Expand Down Expand Up @@ -362,6 +383,7 @@ allOf:
const: apple,t6030-dcpext
required:
- compatible
then: {}
else:
properties:
mux-controls:
Expand All @@ -379,12 +401,39 @@ allOf:
then:
required:
- apple,bw-scratch
- if:
properties:
compatible:
contains:
enum: ['apple,t6050-dcp', 'apple,t6050-dcpext']
then:
required:
- apple,clock-ids
- memory-region
- memory-region-names
- apple,firmware-compat
properties:
apple,firmware-compat:
items:
- const: 27
- const: 0
- const: 0
else:
properties:
clocks:
maxItems: 2
clock-names:
items:
- const: clock-154
- const: clock-194
apple,clock-ids: false
apple,firmware-physical-regs: false
- if:
not:
properties:
compatible:
contains:
enum: ['apple,t8140-dcp', 'apple,t8140-dcpext']
enum: ['apple,t8140-dcp', 'apple,t8140-dcpext', 'apple,t6050-dcp', 'apple,t6050-dcpext']
then:
properties:
apple,power-lut-data-x: false
Expand All @@ -396,7 +445,8 @@ allOf:
properties:
compatible:
contains:
enum: ['apple,t8140-dcp', 'apple,t8140-dcpext']
enum: ['apple,t8140-dcp', 'apple,t8140-dcpext',
'apple,t6050-dcp', 'apple,t6050-dcpext']
then:
properties:
resets: false
Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/apple/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ appledrm-$(CONFIG_DRM_APPLE_KUNIT_TEST) += dcp_external_announce_test.o
appledrm-$(CONFIG_DRM_APPLE_KUNIT_TEST) += dcp_external_relink_test.o
appledrm-$(CONFIG_DRM_APPLE_KUNIT_TEST) += dcp_dropped_swap_test.o
appledrm-y += iomfb_v26_6.o iomfb_v26_6_link.o j613_dcp_activate.o
appledrm-y += iomfb_v27.o
appledrm-y += epic/dpavservep.o
appledrm-y += plane.o

Expand Down
61 changes: 57 additions & 4 deletions drivers/gpu/drm/apple/afk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
/* Copyright 2022 Sven Peter <sven@svenpeter.dev> */

#include <linux/bitfield.h>
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
Expand Down Expand Up @@ -106,6 +108,7 @@ struct apple_dcp_afkep *afk_init(struct apple_dcp *dcp, u32 endpoint,

afkep->ops = ops;
afkep->dcp = dcp;
afkep->wire_v2 = dcp->fw_compat == DCP_FIRMWARE_V_27_0;
afkep->endpoint = endpoint;
afkep->wq = alloc_ordered_workqueue("apple-dcp-afkep%02x",
WQ_MEM_RECLAIM, endpoint);
Expand Down Expand Up @@ -1371,7 +1374,7 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel,
return;
}
ret = parse_epic_service_init(&ctx, &epic_name, &epic_class, &epic_unit,
ep->dcp->fw_compat == DCP_FIRMWARE_H17P);
(ep->dcp->fw_compat == DCP_FIRMWARE_H17P || ep->dcp->fw_compat == DCP_FIRMWARE_V_27_0));
if (ret) {
dev_err(ep->dcp->dev,
"AFK[ep:%02x]: failed to extract init props: %d\n",
Expand Down Expand Up @@ -1464,6 +1467,8 @@ static void afk_recv_handle_init(struct apple_dcp_afkep *ep, u32 channel,
}
if (ops->prepare)
afk_service_publish(service);
if (ops->init_props)
ops->init_props(service, epic_unit, props, props_size);
if (ops->init)
ops->init(service, epic_name, epic_class, epic_unit);
dev_info(ep->dcp->dev, "AFK[ep:%02x]: new service %s on channel %d\n",
Expand Down Expand Up @@ -1749,6 +1754,43 @@ static void afk_v2_status(struct apple_dcp_afkep *ep,
dev_warn(ep->dcp->dev, "AFKV2 error reply failed: %d\n", ret);
}

static int afk_v27_access_remote(struct apple_dcp_afkep *ep, u64 dva, void *buffer,
size_t size, bool to_remote, bool copy)
{
struct iommu_domain *domain = iommu_get_domain_for_dev(ep->dcp->dev);
size_t off = 0;

if (!domain || !dva || size > SZ_1M || size > U64_MAX - dva)
return -EINVAL;
while (off < size) {
phys_addr_t pa = iommu_iova_to_phys(domain, dva + off);
size_t chunk = min_t(size_t, size - off,
PAGE_SIZE - ((dva + off) & ~PAGE_MASK));
void *cpu;

if (!pa) {
dev_err_ratelimited(ep->dcp->dev,
"AFK[ep:%02x]: unmapped remote buffer %#llx + %#zx (%s)\n",
ep->endpoint, dva, off, to_remote ? "reply" : "request");
return -ENXIO;
}
if (!copy) {
off += chunk;
continue;
}
cpu = memremap(pa, chunk, MEMREMAP_WB);
if (!cpu)
return -ENOMEM;
if (to_remote)
memcpy(cpu, buffer + off, chunk);
else
memcpy(buffer + off, cpu, chunk);
memunmap(cpu);
off += chunk;
}
return 0;
}

static int afk_v2_access_owned(struct apple_epic_service *service, u64 dva,
void *buffer, size_t size, bool to_peer, bool copy)
{
Expand Down Expand Up @@ -1792,6 +1834,9 @@ static int afk_v2_access_owned(struct apple_epic_service *service, u64 dva,
break;
}
spin_unlock_irqrestore(&service->lock, flags);
/* T6050 callbacks may refer to firmware-owned buffers in the retained DART. */
if (ret && service->ep->dcp->fw_compat == DCP_FIRMWARE_V_27_0)
ret = afk_v27_access_remote(service->ep, dva, buffer, size, to_peer, copy);
if (ret)
dev_warn_ratelimited(service->ep->dcp->dev,
"AFKV2 unowned buffer: ep=%u interface=%u size=%zu write=%u\n",
Expand Down Expand Up @@ -2010,7 +2055,8 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type,
hdr_len = sizeof(*ehdr) + sizeof(*c);
if (data_size < hdr_len)
goto too_small;
if (ep->dcp->hw.iomfb_method_profile != DCP_IOMFB_METHODS_H17G &&
if (ep->dcp->fw_compat == DCP_FIRMWARE_H17P &&
ep->dcp->hw.iomfb_method_profile != DCP_IOMFB_METHODS_H17G &&
!afk_validate_h17p_header(data, data_size)) {
dev_err(ep->dcp->dev,
"AFK[ep:%02x]: invalid compact message length\n",
Expand All @@ -2028,7 +2074,7 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type,
* queue channel at face value binds "system" to 0 and makes
* every later announce and report look like a duplicate.
*/
channel = le16_to_cpup((__le16 *)(data + 2));
channel = get_unaligned_le16(data + 2);

/*
* Normalise into the wide sub-header the rest of this file
Expand All @@ -2050,6 +2096,7 @@ static void afk_recv_handle(struct apple_dcp_afkep *ep, u32 channel, u32 type,
payload = data + hdr_len;
payload_size = data_size - hdr_len;


trace_afk_recv_handle(ep, channel, type, data_size, ehdr, eshdr);


Expand Down Expand Up @@ -2394,7 +2441,7 @@ static int afk_send_epic_token(struct apple_dcp_afkep *ep, u32 channel, u16 tag,
}

spin_lock_irqsave(&ep->lock, flags);
if (ep->stopping) {
if (ep->stopping || !ep->txbfr.ready) {
ret = -ESHUTDOWN;
goto out;
}
Expand All @@ -2408,6 +2455,12 @@ static int afk_send_epic_token(struct apple_dcp_afkep *ep, u32 channel, u16 tag,
dma_rmb();
rptr = le32_to_cpu(*ep->txbfr.rptr);
wptr = le32_to_cpu(*ep->txbfr.wptr);
if (rptr >= ep->txbfr.bufsz || wptr >= ep->txbfr.bufsz ||
!IS_ALIGNED(rptr, ep->txbfr.stride) ||
!IS_ALIGNED(wptr, ep->txbfr.stride)) {
ret = -EPROTO;
goto out;
}
trace_afk_send_rwptr_pre(ep, rptr, wptr);
total_epic_size = sizeof(*ehdr) +
(ep->wire_v2 ? sizeof(struct epic_sub_hdr_h17p) : sizeof(*eshdr)) +
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/apple/afk.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ struct apple_epic_service_ops {
const char *class, s64 unit);
void (*init)(struct apple_epic_service *service, const char *name,
const char *class, s64 unit);
/* Consumed synchronously before init publishes service readiness. */
void (*init_props)(struct apple_epic_service *service, s64 unit,
const void *props, size_t size);
int (*call)(struct apple_epic_service *service, u32 idx,
const void *data, size_t data_size, void *reply,
size_t reply_size);
Expand Down
46 changes: 46 additions & 0 deletions drivers/gpu/drm/apple/dcp-fabric.c
Original file line number Diff line number Diff line change
Expand Up @@ -1761,12 +1761,51 @@ int dcp_tunnel_crossbar_down(struct apple_dcp *dcp, u32 unit)
* The output is the borrowed Type-C route's, or the fixed route's. Other
* SoCs clock it at select. Runs inside a DCP apcall: only tb_lock.
*/
static int dcp_direct_crossbar_link_t6050(struct apple_dcp *dcp, bool up)
{
typeof(&apple_dp_phy_link_config) get_config;
typeof(&apple_dpxbar_link_configure) configure;
struct mux_control *xbar;
unsigned int pclk;
bool uhbr;
int ret;

guard(mutex)(&dcp->tb_lock);
/* A borrowed Type-C route has its own mux; xbar remains the fixed
* output's mux (or NULL on a Type-C-only pipeline). */
xbar = dcp->active_typec_route ?
dcp->active_typec_route->active_xbar : dcp->xbar;
if (dcp->dptx_tunnel || !dcp->phy || !xbar)
return 0;
get_config = symbol_get(apple_dp_phy_link_config);
if (!get_config)
return dcp->fw_compat == DCP_FIRMWARE_V_27_0 ? -ENODEV : 0;
ret = get_config(dcp->phy, &pclk, &uhbr);
symbol_put(apple_dp_phy_link_config);
if (ret == -EOPNOTSUPP)
return 0;
if (!up && ret == -ENOLINK)
ret = 0;
if (ret)
return ret;
if (!up)
return dcp_dpxbar_link(xbar, false);
configure = symbol_get(apple_dpxbar_link_configure);
if (!configure)
return -ENODEV;
ret = configure(xbar, pclk, uhbr);
symbol_put(apple_dpxbar_link_configure);
return ret ? ret : dcp_dpxbar_link(xbar, true);
}

int dcp_direct_crossbar_link(struct apple_dcp *dcp, bool up)
{
struct apple_dcp_typec_route *route;
struct mux_control *xbar = NULL;
int ret;

if (dcp->fw_compat == DCP_FIRMWARE_V_27_0)
return dcp_direct_crossbar_link_t6050(dcp, up);
if (!of_machine_is_compatible("apple,t6030"))
return 0;
guard(mutex)(&dcp->tb_lock);
Expand Down Expand Up @@ -4114,3 +4153,10 @@ void dcp_fabric_shutdown_dptx(struct apple_dcp *dcp)
}
}
}

int dcp_typec_test_link(struct platform_device *pdev, bool enabled)
{
guard(mutex)(&dcp_typec_fabric_lock);
return enabled ? dcp_dptx_connect_oob(pdev, 0) :
dcp_dptx_disconnect_oob(pdev, 0);
}
2 changes: 2 additions & 0 deletions drivers/gpu/drm/apple/dcp-fabric.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,6 @@ int dcp_dptx_connect(struct apple_dcp *dcp, u32 port);
int dcp_dptx_disconnect(struct apple_dcp *dcp, u32 port);
bool dcp_is_external_h17p(struct apple_dcp *dcp);

int dcp_typec_test_link(struct platform_device *pdev, bool enabled);

#endif /* __APPLE_DCP_FABRIC_H__ */
Loading