1 /* SPDX-License-Identifier: MIT */ 2 /* 3 * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 18 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 * USE OR OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * The above copyright notice and this permission notice (including the 23 * next paragraph) shall be included in all copies or substantial portions 24 * of the Software. 25 * 26 */ 27 28 #include <linux/gpio/machine.h> 29 #include "amdgpu.h" 30 #include "isp_v4_1_1.h" 31 32 #define ISP_PERFORMANCE_STATE_LOW 0 33 #define ISP_PERFORMANCE_STATE_HIGH 1 34 35 #define ISP_HIGH_PERFORMANC_XCLK 788 36 #define ISP_HIGH_PERFORMANC_ICLK 788 37 38 static const unsigned int isp_4_1_1_int_srcid[MAX_ISP411_INT_SRC] = { 39 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9, 40 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT10, 41 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT11, 42 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12, 43 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT13, 44 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT14, 45 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT15, 46 ISP_4_1__SRCID__ISP_RINGBUFFER_WPT16 47 }; 48 49 static struct gpiod_lookup_table isp_gpio_table = { 50 .dev_id = "amd_isp_capture", 51 .table = { 52 GPIO_LOOKUP("AMDI0030:00", 85, "enable_isp", GPIO_ACTIVE_HIGH), 53 { } 54 }, 55 }; 56 57 static struct gpiod_lookup_table isp_sensor_gpio_table = { 58 .dev_id = "i2c-ov05c10", 59 .table = { 60 GPIO_LOOKUP("amdisp-pinctrl", 0, "enable", GPIO_ACTIVE_HIGH), 61 { } 62 }, 63 }; 64 65 static int isp_poweroff(struct generic_pm_domain *genpd) 66 { 67 struct amdgpu_isp *isp = container_of(genpd, struct amdgpu_isp, ispgpd); 68 struct amdgpu_device *adev = isp->adev; 69 70 return amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ISP, true, 0); 71 } 72 73 static int isp_poweron(struct generic_pm_domain *genpd) 74 { 75 struct amdgpu_isp *isp = container_of(genpd, struct amdgpu_isp, ispgpd); 76 struct amdgpu_device *adev = isp->adev; 77 78 return amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_ISP, false, 0); 79 } 80 81 static int isp_set_performance_state(struct generic_pm_domain *genpd, 82 unsigned int state) 83 { 84 struct amdgpu_isp *isp = container_of(genpd, struct amdgpu_isp, ispgpd); 85 struct amdgpu_device *adev = isp->adev; 86 u32 iclk, xclk; 87 int ret; 88 89 switch (state) { 90 case ISP_PERFORMANCE_STATE_HIGH: 91 xclk = ISP_HIGH_PERFORMANC_XCLK; 92 iclk = ISP_HIGH_PERFORMANC_ICLK; 93 break; 94 case ISP_PERFORMANCE_STATE_LOW: 95 /* isp runs at default lowest clock-rate on power-on, do nothing */ 96 return 0; 97 default: 98 return -EINVAL; 99 } 100 101 ret = amdgpu_dpm_set_soft_freq_range(adev, PP_ISPXCLK, xclk, 0); 102 if (ret) { 103 drm_err(&adev->ddev, "failed to set xclk %u to %u: %d\n", 104 xclk, state, ret); 105 return ret; 106 } 107 108 ret = amdgpu_dpm_set_soft_freq_range(adev, PP_ISPICLK, iclk, 0); 109 if (ret) { 110 drm_err(&adev->ddev, "failed to set iclk %u to %u: %d\n", 111 iclk, state, ret); 112 return ret; 113 } 114 115 return 0; 116 } 117 118 static int isp_genpd_add_device(struct device *dev, void *data) 119 { 120 struct generic_pm_domain *gpd = data; 121 struct platform_device *pdev = container_of(dev, struct platform_device, dev); 122 struct amdgpu_isp *isp = container_of(gpd, struct amdgpu_isp, ispgpd); 123 struct amdgpu_device *adev = isp->adev; 124 int ret; 125 126 if (!pdev) 127 return -EINVAL; 128 129 if (!dev->type->name) { 130 drm_dbg(&adev->ddev, "Invalid device type to add\n"); 131 goto exit; 132 } 133 134 if (strcmp(dev->type->name, "mfd_device")) { 135 drm_dbg(&adev->ddev, "Invalid isp mfd device %s to add\n", pdev->mfd_cell->name); 136 goto exit; 137 } 138 139 ret = pm_genpd_add_device(gpd, dev); 140 if (ret) { 141 drm_err(&adev->ddev, "Failed to add dev %s to genpd %d\n", 142 pdev->mfd_cell->name, ret); 143 return -ENODEV; 144 } 145 146 exit: 147 /* Continue to add */ 148 return 0; 149 } 150 151 static int isp_genpd_remove_device(struct device *dev, void *data) 152 { 153 struct generic_pm_domain *gpd = data; 154 struct platform_device *pdev = container_of(dev, struct platform_device, dev); 155 struct amdgpu_isp *isp = container_of(gpd, struct amdgpu_isp, ispgpd); 156 struct amdgpu_device *adev = isp->adev; 157 int ret; 158 159 if (!pdev) 160 return -EINVAL; 161 162 if (!dev->type->name) { 163 drm_dbg(&adev->ddev, "Invalid device type to remove\n"); 164 goto exit; 165 } 166 167 if (strcmp(dev->type->name, "mfd_device")) { 168 drm_dbg(&adev->ddev, "Invalid isp mfd device %s to remove\n", 169 pdev->mfd_cell->name); 170 goto exit; 171 } 172 173 ret = pm_genpd_remove_device(dev); 174 if (ret) { 175 drm_err(&adev->ddev, "Failed to remove dev from genpd %d\n", ret); 176 return -ENODEV; 177 } 178 179 exit: 180 /* Continue to remove */ 181 return 0; 182 } 183 184 static int isp_v4_1_1_hw_init(struct amdgpu_isp *isp) 185 { 186 struct amdgpu_device *adev = isp->adev; 187 int idx, int_idx, num_res, r; 188 u8 isp_dev_hid[ACPI_ID_LEN]; 189 u64 isp_base; 190 191 if (adev->rmmio_size == 0 || adev->rmmio_size < 0x5289) 192 return -EINVAL; 193 194 r = amdgpu_acpi_get_isp4_dev_hid(&isp_dev_hid); 195 if (r) { 196 drm_dbg(&adev->ddev, "Invalid isp platform detected (%d)", r); 197 /* allow GPU init to progress */ 198 return 0; 199 } 200 201 /* add GPIO resources required for OMNI5C10 sensor */ 202 if (!strcmp("OMNI5C10", isp_dev_hid)) { 203 gpiod_add_lookup_table(&isp_gpio_table); 204 gpiod_add_lookup_table(&isp_sensor_gpio_table); 205 } 206 207 isp_base = adev->rmmio_base; 208 209 isp->ispgpd.name = "ISP_v_4_1_1"; 210 isp->ispgpd.power_off = isp_poweroff; 211 isp->ispgpd.power_on = isp_poweron; 212 isp->ispgpd.set_performance_state = isp_set_performance_state; 213 214 r = pm_genpd_init(&isp->ispgpd, NULL, true); 215 if (r) { 216 drm_err(&adev->ddev, "failed to initialize genpd (%d)\n", r); 217 return -EINVAL; 218 } 219 220 isp->isp_cell = kcalloc(3, sizeof(struct mfd_cell), GFP_KERNEL); 221 if (!isp->isp_cell) { 222 r = -ENOMEM; 223 drm_err(&adev->ddev, "isp mfd cell alloc failed (%d)\n", r); 224 goto failure; 225 } 226 227 num_res = MAX_ISP411_MEM_RES + MAX_ISP411_INT_SRC; 228 229 isp->isp_res = kcalloc(num_res, sizeof(struct resource), 230 GFP_KERNEL); 231 if (!isp->isp_res) { 232 r = -ENOMEM; 233 drm_err(&adev->ddev, "isp mfd resource alloc failed (%d)\n", r); 234 goto failure; 235 } 236 237 isp->isp_pdata = kzalloc(sizeof(*isp->isp_pdata), GFP_KERNEL); 238 if (!isp->isp_pdata) { 239 r = -ENOMEM; 240 drm_err(&adev->ddev, "isp platform data alloc failed (%d)\n", r); 241 goto failure; 242 } 243 244 /* initialize isp platform data */ 245 isp->isp_pdata->adev = (void *)adev; 246 isp->isp_pdata->asic_type = adev->asic_type; 247 isp->isp_pdata->base_rmmio_size = adev->rmmio_size; 248 249 isp->isp_res[0].name = "isp_4_1_1_reg"; 250 isp->isp_res[0].flags = IORESOURCE_MEM; 251 isp->isp_res[0].start = isp_base; 252 isp->isp_res[0].end = isp_base + ISP_REGS_OFFSET_END; 253 254 isp->isp_res[1].name = "isp_4_1_1_phy0_reg"; 255 isp->isp_res[1].flags = IORESOURCE_MEM; 256 isp->isp_res[1].start = isp_base + ISP411_PHY0_OFFSET; 257 isp->isp_res[1].end = isp_base + ISP411_PHY0_OFFSET + ISP411_PHY0_SIZE; 258 259 for (idx = MAX_ISP411_MEM_RES, int_idx = 0; idx < num_res; idx++, int_idx++) { 260 isp->isp_res[idx].name = "isp_4_1_1_irq"; 261 isp->isp_res[idx].flags = IORESOURCE_IRQ; 262 isp->isp_res[idx].start = 263 amdgpu_irq_create_mapping(adev, isp_4_1_1_int_srcid[int_idx]); 264 isp->isp_res[idx].end = 265 isp->isp_res[idx].start; 266 } 267 268 isp->isp_cell[0].name = "amd_isp_capture"; 269 isp->isp_cell[0].num_resources = num_res; 270 isp->isp_cell[0].resources = &isp->isp_res[0]; 271 isp->isp_cell[0].platform_data = isp->isp_pdata; 272 isp->isp_cell[0].pdata_size = sizeof(struct isp_platform_data); 273 274 /* initialize isp i2c platform data */ 275 isp->isp_i2c_res = kcalloc(1, sizeof(struct resource), GFP_KERNEL); 276 if (!isp->isp_i2c_res) { 277 r = -ENOMEM; 278 drm_err(&adev->ddev, "isp mfd res alloc failed (%d)\n", r); 279 goto failure; 280 } 281 282 isp->isp_i2c_res[0].name = "isp_i2c0_reg"; 283 isp->isp_i2c_res[0].flags = IORESOURCE_MEM; 284 isp->isp_i2c_res[0].start = isp_base + ISP411_I2C0_OFFSET; 285 isp->isp_i2c_res[0].end = isp_base + ISP411_I2C0_OFFSET + ISP411_I2C0_SIZE; 286 287 isp->isp_cell[1].name = "amd_isp_i2c_designware"; 288 isp->isp_cell[1].num_resources = 1; 289 isp->isp_cell[1].resources = &isp->isp_i2c_res[0]; 290 isp->isp_cell[1].platform_data = isp->isp_pdata; 291 isp->isp_cell[1].pdata_size = sizeof(struct isp_platform_data); 292 293 /* initialize isp gpiochip platform data */ 294 isp->isp_gpio_res = kcalloc(1, sizeof(struct resource), GFP_KERNEL); 295 if (!isp->isp_gpio_res) { 296 r = -ENOMEM; 297 drm_err(&adev->ddev, "isp gpio resource alloc failed (%d)\n", r); 298 goto failure; 299 } 300 301 isp->isp_gpio_res[0].name = "isp_gpio_reg"; 302 isp->isp_gpio_res[0].flags = IORESOURCE_MEM; 303 isp->isp_gpio_res[0].start = isp_base + ISP411_GPIO_SENSOR_OFFSET; 304 isp->isp_gpio_res[0].end = isp_base + ISP411_GPIO_SENSOR_OFFSET + 305 ISP411_GPIO_SENSOR_SIZE; 306 307 isp->isp_cell[2].name = "amdisp-pinctrl"; 308 isp->isp_cell[2].num_resources = 1; 309 isp->isp_cell[2].resources = &isp->isp_gpio_res[0]; 310 isp->isp_cell[2].platform_data = isp->isp_pdata; 311 isp->isp_cell[2].pdata_size = sizeof(struct isp_platform_data); 312 313 /* add only amd_isp_capture and amd_isp_i2c_designware to genpd */ 314 r = mfd_add_hotplug_devices(isp->parent, isp->isp_cell, 2); 315 if (r) { 316 drm_err(&adev->ddev, "add mfd hotplug device failed (%d)\n", r); 317 goto failure; 318 } 319 320 r = device_for_each_child(isp->parent, &isp->ispgpd, 321 isp_genpd_add_device); 322 if (r) { 323 drm_err(&adev->ddev, "failed to add devices to genpd (%d)\n", r); 324 goto failure; 325 } 326 327 r = mfd_add_hotplug_devices(isp->parent, &isp->isp_cell[2], 1); 328 if (r) { 329 drm_err(&adev->ddev, "add pinctl hotplug device failed (%d)\n", r); 330 goto failure; 331 } 332 333 return 0; 334 335 failure: 336 337 kfree(isp->isp_pdata); 338 kfree(isp->isp_res); 339 kfree(isp->isp_cell); 340 kfree(isp->isp_i2c_res); 341 kfree(isp->isp_gpio_res); 342 343 return r; 344 } 345 346 static int isp_v4_1_1_hw_fini(struct amdgpu_isp *isp) 347 { 348 device_for_each_child(isp->parent, NULL, 349 isp_genpd_remove_device); 350 351 mfd_remove_devices(isp->parent); 352 353 kfree(isp->isp_res); 354 kfree(isp->isp_cell); 355 kfree(isp->isp_pdata); 356 kfree(isp->isp_i2c_res); 357 kfree(isp->isp_gpio_res); 358 359 return 0; 360 } 361 362 static const struct isp_funcs isp_v4_1_1_funcs = { 363 .hw_init = isp_v4_1_1_hw_init, 364 .hw_fini = isp_v4_1_1_hw_fini, 365 }; 366 367 void isp_v4_1_1_set_isp_funcs(struct amdgpu_isp *isp) 368 { 369 isp->funcs = &isp_v4_1_1_funcs; 370 } 371