Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc5 277 lines 6.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2 3#include <linux/component.h> 4#include <linux/iopoll.h> 5#include <linux/of.h> 6#include <linux/platform_device.h> 7 8#include <drm/drm_bridge.h> 9#include <drm/drm_mipi_dsi.h> 10 11#define DSI_GEN_HDR 0x6c 12#define DSI_GEN_PLD_DATA 0x70 13 14#define DSI_CMD_PKT_STATUS 0x74 15 16#define GEN_PLD_R_EMPTY BIT(4) 17#define GEN_PLD_W_FULL BIT(3) 18#define GEN_PLD_W_EMPTY BIT(2) 19#define GEN_CMD_FULL BIT(1) 20#define GEN_CMD_EMPTY BIT(0) 21#define GEN_RD_CMD_BUSY BIT(6) 22#define CMD_PKT_STATUS_TIMEOUT_US 20000 23 24struct adp_mipi_drv_private { 25 struct mipi_dsi_host dsi; 26 struct drm_bridge bridge; 27 struct drm_bridge *next_bridge; 28 void __iomem *mipi; 29}; 30 31#define mipi_to_adp(x) container_of(x, struct adp_mipi_drv_private, dsi) 32 33static int adp_dsi_gen_pkt_hdr_write(struct adp_mipi_drv_private *adp, u32 hdr_val) 34{ 35 int ret; 36 u32 val, mask; 37 38 ret = readl_poll_timeout(adp->mipi + DSI_CMD_PKT_STATUS, 39 val, !(val & GEN_CMD_FULL), 1000, 40 CMD_PKT_STATUS_TIMEOUT_US); 41 if (ret) { 42 dev_err(adp->dsi.dev, "failed to get available command FIFO\n"); 43 return ret; 44 } 45 46 writel(hdr_val, adp->mipi + DSI_GEN_HDR); 47 48 mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY; 49 ret = readl_poll_timeout(adp->mipi + DSI_CMD_PKT_STATUS, 50 val, (val & mask) == mask, 51 1000, CMD_PKT_STATUS_TIMEOUT_US); 52 if (ret) { 53 dev_err(adp->dsi.dev, "failed to write command FIFO\n"); 54 return ret; 55 } 56 57 return 0; 58} 59 60static int adp_dsi_write(struct adp_mipi_drv_private *adp, 61 const struct mipi_dsi_packet *packet) 62{ 63 const u8 *tx_buf = packet->payload; 64 int len = packet->payload_length, pld_data_bytes = sizeof(u32), ret; 65 __le32 word; 66 u32 val; 67 68 while (len) { 69 if (len < pld_data_bytes) { 70 word = 0; 71 memcpy(&word, tx_buf, len); 72 writel(le32_to_cpu(word), adp->mipi + DSI_GEN_PLD_DATA); 73 len = 0; 74 } else { 75 memcpy(&word, tx_buf, pld_data_bytes); 76 writel(le32_to_cpu(word), adp->mipi + DSI_GEN_PLD_DATA); 77 tx_buf += pld_data_bytes; 78 len -= pld_data_bytes; 79 } 80 81 ret = readl_poll_timeout(adp->mipi + DSI_CMD_PKT_STATUS, 82 val, !(val & GEN_PLD_W_FULL), 1000, 83 CMD_PKT_STATUS_TIMEOUT_US); 84 if (ret) { 85 dev_err(adp->dsi.dev, 86 "failed to get available write payload FIFO\n"); 87 return ret; 88 } 89 } 90 91 word = 0; 92 memcpy(&word, packet->header, sizeof(packet->header)); 93 return adp_dsi_gen_pkt_hdr_write(adp, le32_to_cpu(word)); 94} 95 96static int adp_dsi_read(struct adp_mipi_drv_private *adp, 97 const struct mipi_dsi_msg *msg) 98{ 99 int i, j, ret, len = msg->rx_len; 100 u8 *buf = msg->rx_buf; 101 u32 val; 102 103 /* Wait end of the read operation */ 104 ret = readl_poll_timeout(adp->mipi + DSI_CMD_PKT_STATUS, 105 val, !(val & GEN_RD_CMD_BUSY), 106 1000, CMD_PKT_STATUS_TIMEOUT_US); 107 if (ret) { 108 dev_err(adp->dsi.dev, "Timeout during read operation\n"); 109 return ret; 110 } 111 112 for (i = 0; i < len; i += 4) { 113 /* Read fifo must not be empty before all bytes are read */ 114 ret = readl_poll_timeout(adp->mipi + DSI_CMD_PKT_STATUS, 115 val, !(val & GEN_PLD_R_EMPTY), 116 1000, CMD_PKT_STATUS_TIMEOUT_US); 117 if (ret) { 118 dev_err(adp->dsi.dev, "Read payload FIFO is empty\n"); 119 return ret; 120 } 121 122 val = readl(adp->mipi + DSI_GEN_PLD_DATA); 123 for (j = 0; j < 4 && j + i < len; j++) 124 buf[i + j] = val >> (8 * j); 125 } 126 127 return ret; 128} 129 130static ssize_t adp_dsi_host_transfer(struct mipi_dsi_host *host, 131 const struct mipi_dsi_msg *msg) 132{ 133 struct adp_mipi_drv_private *adp = mipi_to_adp(host); 134 struct mipi_dsi_packet packet; 135 int ret, nb_bytes; 136 137 ret = mipi_dsi_create_packet(&packet, msg); 138 if (ret) { 139 dev_err(adp->dsi.dev, "failed to create packet: %d\n", ret); 140 return ret; 141 } 142 143 ret = adp_dsi_write(adp, &packet); 144 if (ret) 145 return ret; 146 147 if (msg->rx_buf && msg->rx_len) { 148 ret = adp_dsi_read(adp, msg); 149 if (ret) 150 return ret; 151 nb_bytes = msg->rx_len; 152 } else { 153 nb_bytes = packet.size; 154 } 155 156 return nb_bytes; 157} 158 159static int adp_dsi_bind(struct device *dev, struct device *master, void *data) 160{ 161 return 0; 162} 163 164static void adp_dsi_unbind(struct device *dev, struct device *master, void *data) 165{ 166} 167 168static const struct component_ops adp_dsi_component_ops = { 169 .bind = adp_dsi_bind, 170 .unbind = adp_dsi_unbind, 171}; 172 173static int adp_dsi_host_attach(struct mipi_dsi_host *host, 174 struct mipi_dsi_device *dev) 175{ 176 struct adp_mipi_drv_private *adp = mipi_to_adp(host); 177 struct drm_bridge *next; 178 int ret; 179 180 next = devm_drm_of_get_bridge(adp->dsi.dev, adp->dsi.dev->of_node, 1, 0); 181 if (IS_ERR(next)) 182 return PTR_ERR(next); 183 184 adp->next_bridge = next; 185 186 drm_bridge_add(&adp->bridge); 187 188 ret = component_add(host->dev, &adp_dsi_component_ops); 189 if (ret) { 190 pr_err("failed to add dsi_host component: %d\n", ret); 191 drm_bridge_remove(&adp->bridge); 192 return ret; 193 } 194 195 return 0; 196} 197 198static int adp_dsi_host_detach(struct mipi_dsi_host *host, 199 struct mipi_dsi_device *dev) 200{ 201 struct adp_mipi_drv_private *adp = mipi_to_adp(host); 202 203 component_del(host->dev, &adp_dsi_component_ops); 204 drm_bridge_remove(&adp->bridge); 205 return 0; 206} 207 208static const struct mipi_dsi_host_ops adp_dsi_host_ops = { 209 .transfer = adp_dsi_host_transfer, 210 .attach = adp_dsi_host_attach, 211 .detach = adp_dsi_host_detach, 212}; 213 214static int adp_dsi_bridge_attach(struct drm_bridge *bridge, 215 struct drm_encoder *encoder, 216 enum drm_bridge_attach_flags flags) 217{ 218 struct adp_mipi_drv_private *adp = 219 container_of(bridge, struct adp_mipi_drv_private, bridge); 220 221 return drm_bridge_attach(encoder, adp->next_bridge, bridge, flags); 222} 223 224static const struct drm_bridge_funcs adp_dsi_bridge_funcs = { 225 .attach = adp_dsi_bridge_attach, 226}; 227 228static int adp_mipi_probe(struct platform_device *pdev) 229{ 230 struct adp_mipi_drv_private *adp; 231 232 adp = devm_drm_bridge_alloc(&pdev->dev, struct adp_mipi_drv_private, 233 bridge, &adp_dsi_bridge_funcs); 234 if (IS_ERR(adp)) 235 return PTR_ERR(adp); 236 237 adp->mipi = devm_platform_ioremap_resource(pdev, 0); 238 if (IS_ERR(adp->mipi)) { 239 dev_err(&pdev->dev, "failed to map mipi mmio"); 240 return PTR_ERR(adp->mipi); 241 } 242 243 adp->dsi.dev = &pdev->dev; 244 adp->dsi.ops = &adp_dsi_host_ops; 245 adp->bridge.of_node = pdev->dev.of_node; 246 adp->bridge.type = DRM_MODE_CONNECTOR_DSI; 247 dev_set_drvdata(&pdev->dev, adp); 248 return mipi_dsi_host_register(&adp->dsi); 249} 250 251static void adp_mipi_remove(struct platform_device *pdev) 252{ 253 struct device *dev = &pdev->dev; 254 struct adp_mipi_drv_private *adp = dev_get_drvdata(dev); 255 256 mipi_dsi_host_unregister(&adp->dsi); 257} 258 259static const struct of_device_id adp_mipi_of_match[] = { 260 { .compatible = "apple,h7-display-pipe-mipi", }, 261 { }, 262}; 263MODULE_DEVICE_TABLE(of, adp_mipi_of_match); 264 265static struct platform_driver adp_mipi_platform_driver = { 266 .driver = { 267 .name = "adp-mipi", 268 .of_match_table = adp_mipi_of_match, 269 }, 270 .probe = adp_mipi_probe, 271 .remove = adp_mipi_remove, 272}; 273 274module_platform_driver(adp_mipi_platform_driver); 275 276MODULE_DESCRIPTION("Apple Display Pipe MIPI driver"); 277MODULE_LICENSE("GPL");