From 50c0ebb8b3d61d87728c6be403e5737cc1275e90 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 31 Aug 2023 19:08:46 +0900 Subject: [PATCH 01/60] media: apple: Add Apple ISP driver Signed-off-by: Eileen Yoon --- drivers/media/platform/Kconfig | 1 + drivers/media/platform/Makefile | 1 + drivers/media/platform/apple/Kconfig | 5 + drivers/media/platform/apple/Makefile | 3 + drivers/media/platform/apple/isp/.gitignore | 1 + drivers/media/platform/apple/isp/Kconfig | 10 + drivers/media/platform/apple/isp/Makefile | 3 + drivers/media/platform/apple/isp/isp-cam.c | 540 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cam.h | 20 + drivers/media/platform/apple/isp/isp-cmd.c | 544 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 532 ++++++++++++++++ drivers/media/platform/apple/isp/isp-drv.c | 333 ++++++++++ drivers/media/platform/apple/isp/isp-drv.h | 258 ++++++++ drivers/media/platform/apple/isp/isp-fw.c | 605 +++++++++++++++++++ drivers/media/platform/apple/isp/isp-fw.h | 12 + drivers/media/platform/apple/isp/isp-iommu.c | 274 +++++++++ drivers/media/platform/apple/isp/isp-iommu.h | 38 ++ drivers/media/platform/apple/isp/isp-ipc.c | 329 ++++++++++ drivers/media/platform/apple/isp/isp-ipc.h | 26 + drivers/media/platform/apple/isp/isp-regs.h | 62 ++ drivers/media/platform/apple/isp/isp-v4l2.c | 602 ++++++++++++++++++ drivers/media/platform/apple/isp/isp-v4l2.h | 12 + 22 files changed, 4211 insertions(+) create mode 100644 drivers/media/platform/apple/Kconfig create mode 100644 drivers/media/platform/apple/Makefile create mode 100644 drivers/media/platform/apple/isp/.gitignore create mode 100644 drivers/media/platform/apple/isp/Kconfig create mode 100644 drivers/media/platform/apple/isp/Makefile create mode 100644 drivers/media/platform/apple/isp/isp-cam.c create mode 100644 drivers/media/platform/apple/isp/isp-cam.h create mode 100644 drivers/media/platform/apple/isp/isp-cmd.c create mode 100644 drivers/media/platform/apple/isp/isp-cmd.h create mode 100644 drivers/media/platform/apple/isp/isp-drv.c create mode 100644 drivers/media/platform/apple/isp/isp-drv.h create mode 100644 drivers/media/platform/apple/isp/isp-fw.c create mode 100644 drivers/media/platform/apple/isp/isp-fw.h create mode 100644 drivers/media/platform/apple/isp/isp-iommu.c create mode 100644 drivers/media/platform/apple/isp/isp-iommu.h create mode 100644 drivers/media/platform/apple/isp/isp-ipc.c create mode 100644 drivers/media/platform/apple/isp/isp-ipc.h create mode 100644 drivers/media/platform/apple/isp/isp-regs.h create mode 100644 drivers/media/platform/apple/isp/isp-v4l2.c create mode 100644 drivers/media/platform/apple/isp/isp-v4l2.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 91e54215de3a9b..f1ee51920451ca 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -65,6 +65,7 @@ config VIDEO_MUX source "drivers/media/platform/allegro-dvt/Kconfig" source "drivers/media/platform/amlogic/Kconfig" source "drivers/media/platform/amphion/Kconfig" +source "drivers/media/platform/apple/Kconfig" source "drivers/media/platform/aspeed/Kconfig" source "drivers/media/platform/atmel/Kconfig" source "drivers/media/platform/cadence/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 3296ec1ebe16d7..cfeca7de3892a5 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -8,6 +8,7 @@ obj-y += allegro-dvt/ obj-y += amlogic/ obj-y += amphion/ +obj-y += apple/ obj-y += aspeed/ obj-y += atmel/ obj-y += cadence/ diff --git a/drivers/media/platform/apple/Kconfig b/drivers/media/platform/apple/Kconfig new file mode 100644 index 00000000000000..f16508bff5242a --- /dev/null +++ b/drivers/media/platform/apple/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +comment "Apple media platform drivers" + +source "drivers/media/platform/apple/isp/Kconfig" diff --git a/drivers/media/platform/apple/Makefile b/drivers/media/platform/apple/Makefile new file mode 100644 index 00000000000000..d8fe985b0e6c37 --- /dev/null +++ b/drivers/media/platform/apple/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-y += isp/ diff --git a/drivers/media/platform/apple/isp/.gitignore b/drivers/media/platform/apple/isp/.gitignore new file mode 100644 index 00000000000000..bd7fab40e0d98a --- /dev/null +++ b/drivers/media/platform/apple/isp/.gitignore @@ -0,0 +1 @@ +.clang-format diff --git a/drivers/media/platform/apple/isp/Kconfig b/drivers/media/platform/apple/isp/Kconfig new file mode 100644 index 00000000000000..f0e2173640ab73 --- /dev/null +++ b/drivers/media/platform/apple/isp/Kconfig @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_APPLE_ISP + tristate "Apple Silicon Image Signal Processor driver" + select VIDEOBUF2_CORE + select VIDEOBUF2_V4L2 + select VIDEOBUF2_DMA_SG + depends on ARCH_APPLE || COMPILE_TEST + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV diff --git a/drivers/media/platform/apple/isp/Makefile b/drivers/media/platform/apple/isp/Makefile new file mode 100644 index 00000000000000..4649f32987f025 --- /dev/null +++ b/drivers/media/platform/apple/isp/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only +apple-isp-y := isp-cam.o isp-cmd.o isp-drv.o isp-fw.o isp-iommu.o isp-ipc.o isp-v4l2.o +obj-$(CONFIG_VIDEO_APPLE_ISP) += apple-isp.o diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c new file mode 100644 index 00000000000000..6d08248ef44776 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -0,0 +1,540 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include + +#include "isp-cam.h" +#include "isp-cmd.h" +#include "isp-fw.h" +#include "isp-iommu.h" + +struct isp_setfile { + u32 version; + u32 magic; + const char *path; + size_t size; +}; + +struct isp_preset { + u32 index; + u32 width; + u32 height; + u32 x1; + u32 y1; + u32 x2; + u32 y2; + u32 orig_width; + u32 orig_height; +}; + +// clang-format off +static const struct isp_setfile isp_setfiles[] = { + [ISP_IMX248_1820_01] = {0x248, 0x18200103, "isp/1820_01XX.dat", 0x442c}, + [ISP_IMX248_1822_02] = {0x248, 0x18220201, "isp/1822_02XX.dat", 0x442c}, + [ISP_IMX343_5221_02] = {0x343, 0x52210211, "isp/5221_02XX.dat", 0x4870}, + [ISP_IMX354_9251_02] = {0x354, 0x92510208, "isp/9251_02XX.dat", 0xa5ec}, + [ISP_IMX356_4820_01] = {0x356, 0x48200107, "isp/4820_01XX.dat", 0x9324}, + [ISP_IMX356_4820_02] = {0x356, 0x48200206, "isp/4820_02XX.dat", 0x9324}, + [ISP_IMX364_8720_01] = {0x364, 0x87200103, "isp/8720_01XX.dat", 0x36ac}, + [ISP_IMX364_8723_01] = {0x364, 0x87230101, "isp/8723_01XX.dat", 0x361c}, + [ISP_IMX372_3820_01] = {0x372, 0x38200108, "isp/3820_01XX.dat", 0xfdb0}, + [ISP_IMX372_3820_02] = {0x372, 0x38200205, "isp/3820_02XX.dat", 0xfdb0}, + [ISP_IMX372_3820_11] = {0x372, 0x38201104, "isp/3820_11XX.dat", 0xfdb0}, + [ISP_IMX372_3820_12] = {0x372, 0x38201204, "isp/3820_12XX.dat", 0xfdb0}, + [ISP_IMX405_9720_01] = {0x405, 0x97200102, "isp/9720_01XX.dat", 0x92c8}, + [ISP_IMX405_9721_01] = {0x405, 0x97210102, "isp/9721_01XX.dat", 0x9818}, + [ISP_IMX405_9723_01] = {0x405, 0x97230101, "isp/9723_01XX.dat", 0x92c8}, + [ISP_IMX414_2520_01] = {0x414, 0x25200102, "isp/2520_01XX.dat", 0xa444}, + [ISP_IMX503_7820_01] = {0x503, 0x78200109, "isp/7820_01XX.dat", 0xb268}, + [ISP_IMX503_7820_02] = {0x503, 0x78200206, "isp/7820_02XX.dat", 0xb268}, + [ISP_IMX505_3921_01] = {0x505, 0x39210102, "isp/3921_01XX.dat", 0x89b0}, + [ISP_IMX514_2820_01] = {0x514, 0x28200108, "isp/2820_01XX.dat", 0xa198}, + [ISP_IMX514_2820_02] = {0x514, 0x28200205, "isp/2820_02XX.dat", 0xa198}, + [ISP_IMX514_2820_03] = {0x514, 0x28200305, "isp/2820_03XX.dat", 0xa198}, + [ISP_IMX514_2820_04] = {0x514, 0x28200405, "isp/2820_04XX.dat", 0xa198}, + [ISP_IMX558_1921_01] = {0x558, 0x19210106, "isp/1921_01XX.dat", 0xad40}, + [ISP_IMX558_1922_02] = {0x558, 0x19220201, "isp/1922_02XX.dat", 0xad40}, + [ISP_IMX603_7920_01] = {0x603, 0x79200109, "isp/7920_01XX.dat", 0xad2c}, + [ISP_IMX603_7920_02] = {0x603, 0x79200205, "isp/7920_02XX.dat", 0xad2c}, + [ISP_IMX603_7921_01] = {0x603, 0x79210104, "isp/7921_01XX.dat", 0xad90}, + [ISP_IMX613_4920_01] = {0x613, 0x49200108, "isp/4920_01XX.dat", 0x9324}, + [ISP_IMX613_4920_02] = {0x613, 0x49200204, "isp/4920_02XX.dat", 0x9324}, + [ISP_IMX614_2921_01] = {0x614, 0x29210107, "isp/2921_01XX.dat", 0xed6c}, + [ISP_IMX614_2921_02] = {0x614, 0x29210202, "isp/2921_02XX.dat", 0xed6c}, + [ISP_IMX614_2922_02] = {0x614, 0x29220201, "isp/2922_02XX.dat", 0xed6c}, + [ISP_IMX633_3622_01] = {0x633, 0x36220111, "isp/3622_01XX.dat", 0x100d4}, + [ISP_IMX703_7721_01] = {0x703, 0x77210106, "isp/7721_01XX.dat", 0x936c}, + [ISP_IMX703_7722_01] = {0x703, 0x77220106, "isp/7722_01XX.dat", 0xac20}, + [ISP_IMX713_4721_01] = {0x713, 0x47210107, "isp/4721_01XX.dat", 0x936c}, + [ISP_IMX713_4722_01] = {0x713, 0x47220109, "isp/4722_01XX.dat", 0x9218}, + [ISP_IMX714_2022_01] = {0x714, 0x20220107, "isp/2022_01XX.dat", 0xa198}, + [ISP_IMX772_3721_01] = {0x772, 0x37210106, "isp/3721_01XX.dat", 0xfdf8}, + [ISP_IMX772_3721_11] = {0x772, 0x37211106, "isp/3721_11XX.dat", 0xfe14}, + [ISP_IMX772_3722_01] = {0x772, 0x37220104, "isp/3722_01XX.dat", 0xfca4}, + [ISP_IMX772_3723_01] = {0x772, 0x37230106, "isp/3723_01XX.dat", 0xfca4}, + [ISP_IMX814_2123_01] = {0x814, 0x21230101, "isp/2123_01XX.dat", 0xed54}, + [ISP_IMX853_7622_01] = {0x853, 0x76220112, "isp/7622_01XX.dat", 0x247f8}, + [ISP_IMX913_7523_01] = {0x913, 0x75230107, "isp/7523_01XX.dat", 0x247f8}, + [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, + [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, +}; +// clang-format on + +// one day we will do this intelligently +static const struct isp_preset isp_presets[] = { + [ISP_IMX248_1820_01] = { 0, 1280, 720, 8, 8, 1280, 720, 1296, 736 }, +}; + +static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + enum isp_sensor_id id; + int err = 0; + + /* TODO need more datapoints to figure out the sub-versions + * Defaulting to 1st release for now, the calib files aren't too different. + */ + switch (fmt->version) { + case 0x248: + id = ISP_IMX248_1820_01; + break; + case 0x343: + id = ISP_IMX343_5221_02; + break; + case 0x354: + id = ISP_IMX354_9251_02; + break; + case 0x356: + id = ISP_IMX356_4820_01; + break; + case 0x364: + id = ISP_IMX364_8720_01; + break; + case 0x372: + id = ISP_IMX372_3820_01; + break; + case 0x405: + id = ISP_IMX405_9720_01; + break; + case 0x414: + id = ISP_IMX414_2520_01; + break; + case 0x503: + id = ISP_IMX503_7820_01; + break; + case 0x505: + id = ISP_IMX505_3921_01; + break; + case 0x514: + id = ISP_IMX514_2820_01; + break; + case 0x558: + id = ISP_IMX558_1921_01; + break; + case 0x603: + id = ISP_IMX603_7920_01; + break; + case 0x613: + id = ISP_IMX613_4920_01; + break; + case 0x614: + id = ISP_IMX614_2921_01; + break; + case 0x633: + id = ISP_IMX633_3622_01; + break; + case 0x703: + id = ISP_IMX703_7721_01; + break; + case 0x713: + id = ISP_IMX713_4721_01; + break; + case 0x714: + id = ISP_IMX714_2022_01; + break; + case 0x772: + id = ISP_IMX772_3721_01; + break; + case 0x814: + id = ISP_IMX814_2123_01; + break; + case 0x853: + id = ISP_IMX853_7622_01; + break; + case 0x913: + id = ISP_IMX913_7523_01; + break; + case 0xd56: + id = ISP_VD56G0_6221_01; + break; + default: + err = -EINVAL; + break; + } + + if (err) + dev_err(isp->dev, "invalid sensor version: 0x%x\n", + fmt->version); + else + fmt->id = id; + + return err; +} + +static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + int err = 0; + + struct cmd_ch_info *args; /* Too big to allocate on stack */ + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + err = isp_cmd_ch_info_get(isp, ch, args); + if (err) + goto exit; + + dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, + args->module_sn, ch); + + fmt->version = args->version; + fmt->num_presets = args->num_presets; + + pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); + print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); + + err = isp_ch_get_sensor_id(isp, ch); + if (err || (fmt->id != ISP_IMX248_1820_01)) { + dev_err(isp->dev, + "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", + ch); + return -ENODEV; + } + +exit: + kfree(args); + + return err; +} + +static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) +{ + int err = 0; + + struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ + args = kzalloc(sizeof(*args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); + if (err) + goto exit; + + pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); + print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); + +exit: + kfree(args); + + return err; +} + +static void isp_ch_dump_camera_presets(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + for (u32 ps = 0; ps < fmt->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); + } +} + +static int isp_ch_cache_camera_preset(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + const struct isp_preset *preset = &isp_presets[fmt->id]; + size_t total_size; + + isp_ch_dump_camera_presets(isp, ch); + + fmt->preset = preset->index; + + fmt->width = preset->width; + fmt->height = preset->height; + + fmt->x1 = preset->x1; + fmt->y1 = preset->y1; + fmt->x2 = preset->x2; + fmt->y2 = preset->y2; + + /* I really fucking hope they all use NV12. */ + fmt->num_planes = 2; + fmt->plane_size[0] = fmt->width * fmt->height; + fmt->plane_size[1] = fmt->plane_size[0] / 2; + + total_size = 0; + for (int i = 0; i < fmt->num_planes; i++) + total_size += fmt->plane_size[i]; + fmt->total_size = total_size; + + return 0; +} + +static int isp_ch_cache_camera_info(struct apple_isp *isp, u32 ch) +{ + int err; + + err = isp_ch_cache_sensor_info(isp, ch); + if (err) { + dev_err(isp->dev, "ch %d: failed to cache sensor info: %d\n", + ch, err); + return err; + } + + err = isp_ch_cache_camera_preset(isp, ch); + if (err) { + dev_err(isp->dev, "ch %d: failed to cache camera preset: %d\n", + ch, err); + return err; + } + + return 0; +} + +static int isp_detect_camera(struct apple_isp *isp) +{ + int err; + + struct cmd_config_get args; + memset(&args, 0, sizeof(args)); + + err = isp_cmd_config_get(isp, &args); + if (err) + return err; + + pr_info("apple-isp: CISP_CMD_CONFIG_GET: \n"); + print_hex_dump(KERN_INFO, "apple-isp: ", DUMP_PREFIX_NONE, 32, 4, &args, + sizeof(args), false); + + if (!args.num_channels) { + dev_err(isp->dev, "did not detect any channels\n"); + return -ENODEV; + } + + if (args.num_channels > ISP_MAX_CHANNELS) { + dev_warn(isp->dev, "found %d channels when maximum is %d\n", + args.num_channels, ISP_MAX_CHANNELS); + args.num_channels = ISP_MAX_CHANNELS; + } + + if (args.num_channels > 1) { + dev_warn( + isp->dev, + "warning: driver doesn't support multiple channels. Please file a bug report with hardware info & dmesg trace.\n"); + } + + isp->num_channels = args.num_channels; + isp->current_ch = 0; + + return isp_ch_cache_camera_info(isp, isp->current_ch); /* I told you */ +} + +int apple_isp_detect_camera(struct apple_isp *isp) +{ + int err; + + /* RPM must be enabled prior to calling this */ + err = apple_isp_firmware_boot(isp); + if (err) { + dev_err(isp->dev, + "failed to boot firmware for initial sensor detection: %d\n", + err); + return -EPROBE_DEFER; + } + + err = isp_detect_camera(isp); + apple_isp_firmware_shutdown(isp); + + return err; +} + +static int isp_ch_load_setfile(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + const struct isp_setfile *setfile = &isp_setfiles[fmt->id]; + const struct firmware *fw; + u32 magic; + int err; + + err = request_firmware(&fw, setfile->path, isp->dev); + if (err) { + dev_err(isp->dev, "failed to request setfile '%s': %d\n", + setfile->path, err); + return err; + } + + if (fw->size < setfile->size) { + dev_err(isp->dev, "setfile too small (0x%lx/0x%zx)\n", fw->size, + setfile->size); + release_firmware(fw); + return -EINVAL; + } + + magic = be32_to_cpup((__be32 *)fw->data); + if (magic != setfile->magic) { + dev_err(isp->dev, "setfile '%s' corrupted?\n", setfile->path); + release_firmware(fw); + return -EINVAL; + } + + isp_iowrite(isp, isp->data_surf->iova, (void *)fw->data, setfile->size); + release_firmware(fw); + + return isp_cmd_ch_set_file_load(isp, ch, isp->data_surf->iova, + setfile->size); +} + +static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) +{ + struct isp_format *fmt = isp_get_format(isp, ch); + int err; + + /* The setfile isn't requisite but then we don't get calibration */ + err = isp_ch_load_setfile(isp, ch); + if (err) { + dev_err(isp->dev, "warning: calibration data not loaded: %d\n", + err); + } + + err = isp_cmd_ch_sbs_enable(isp, ch, 1); + if (err) + return err; + + err = isp_cmd_ch_buffer_recycle_mode_set( + isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); + if (err) + return err; + + err = isp_cmd_ch_buffer_recycle_start(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset); + if (err) + return err; + + err = isp_cmd_ch_crop_set(isp, ch, fmt->x1, fmt->y1, fmt->x2, fmt->y2); + if (err) + return err; + + err = isp_cmd_ch_output_config_set(isp, ch, fmt->width, fmt->height, + CISP_COLORSPACE_REC709, + CISP_OUTPUT_FORMAT_NV12); + if (err) + return err; + + err = isp_cmd_ch_preview_stream_set(isp, ch, 1); + if (err) + return err; + + err = isp_cmd_ch_cnr_start(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_mbnr_enable(isp, ch, 0, 1, 1); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_motion_history_start(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_ae_fd_scene_metering_config_set(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_ae_metering_mode_set(isp, ch, 3); + if (err) + return err; + + err = isp_cmd_ch_ae_stability_set(isp, ch, 32); + if (err) + return err; + + err = isp_cmd_ch_ae_stability_to_stable_set(isp, ch, 20); + if (err) + return err; + + err = isp_cmd_ch_sif_pixel_format_set(isp, ch); + if (err) + return err; + + err = isp_cmd_ch_ae_frame_rate_max_set(isp, ch, ISP_FRAME_RATE_DEN); + if (err) + return err; + + err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN); + if (err) + return err; + + err = isp_cmd_ch_buffer_pool_config_set(isp, ch, CISP_POOL_TYPE_META); + if (err) + return err; + + err = isp_cmd_ch_buffer_pool_config_set(isp, ch, + CISP_POOL_TYPE_META_CAPTURE); + if (err) + return err; + + return 0; +} + +static int isp_configure_capture(struct apple_isp *isp) +{ + return isp_ch_configure_capture(isp, isp->current_ch); +} + +int apple_isp_start_camera(struct apple_isp *isp) +{ + int err; + + err = apple_isp_firmware_boot(isp); + if (err < 0) { + dev_err(isp->dev, "failed to boot firmware: %d\n", err); + return err; + } + + err = isp_configure_capture(isp); + if (err) { + dev_err(isp->dev, "failed to configure capture: %d\n", err); + apple_isp_firmware_shutdown(isp); + return err; + } + + return 0; +} + +void apple_isp_stop_camera(struct apple_isp *isp) +{ + apple_isp_firmware_shutdown(isp); +} + +int apple_isp_start_capture(struct apple_isp *isp) +{ + return isp_cmd_ch_start(isp, 0); // TODO channel mask +} + +void apple_isp_stop_capture(struct apple_isp *isp) +{ + isp_cmd_ch_stop(isp, 0); // TODO channel mask + isp_cmd_ch_buffer_return(isp, isp->current_ch); +} diff --git a/drivers/media/platform/apple/isp/isp-cam.h b/drivers/media/platform/apple/isp/isp-cam.h new file mode 100644 index 00000000000000..126e5806c8c416 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cam.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_CAM_H__ +#define __ISP_CAM_H__ + +#include "isp-drv.h" + +#define ISP_FRAME_RATE_NUM 256 +#define ISP_FRAME_RATE_DEN 7680 + +int apple_isp_detect_camera(struct apple_isp *isp); + +int apple_isp_start_camera(struct apple_isp *isp); +void apple_isp_stop_camera(struct apple_isp *isp); + +int apple_isp_start_capture(struct apple_isp *isp); +void apple_isp_stop_capture(struct apple_isp *isp); + +#endif /* __ISP_CAM_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c new file mode 100644 index 00000000000000..79ffb2b1c33881 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" + +#define CISP_OPCODE_SHIFT 32UL +#define CISP_OPCODE(x) (((u64)(x)) << CISP_OPCODE_SHIFT) +#define CISP_OPCODE_GET(x) (((u64)(x)) >> CISP_OPCODE_SHIFT) + +#define CISP_TIMEOUT msecs_to_jiffies(3000) +#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0)) +#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a))) +#define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) + +static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) +{ + struct isp_channel *chan = isp->chan_io; + struct isp_message *req = &chan->req; + int err; + + req->arg0 = isp->cmd_iova; + req->arg1 = insize; + req->arg2 = outsize; + + isp_iowrite(isp, isp->cmd_iova, args, insize); + err = ipc_chan_send(isp, chan, CISP_TIMEOUT); + if (err) { + u64 opcode; + memcpy(&opcode, args, sizeof(opcode)); + dev_err(isp->dev, + "%s: failed to send OPCODE 0x%04llx: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, CISP_OPCODE_GET(opcode), req->arg0, + req->arg1, req->arg2); + } + + return err; +} + +static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, + u32 outsize) +{ + /* TODO do I need to lock the iova space? */ + int err = cisp_send(isp, args, insize, outsize); + if (err) + return err; + isp_ioread(isp, isp->cmd_iova, args, outsize); + return 0; +} + +int isp_cmd_start(struct apple_isp *isp, u32 mode) +{ + struct cmd_start args = { + .opcode = CISP_OPCODE(CISP_CMD_START), + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_suspend(struct apple_isp *isp) +{ + struct cmd_suspend args = { + .opcode = CISP_OPCODE(CISP_CMD_SUSPEND), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_print_enable(struct apple_isp *isp, u32 enable) +{ + struct cmd_print_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_PRINT_ENABLE), + .enable = enable, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable) +{ + struct cmd_trace_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_TRACE_ENABLE), + .enable = enable, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CONFIG_GET); + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base) +{ + struct cmd_set_isp_pmu_base args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_ISP_PMU_BASE), + .pmu_base = pmu_base, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, + u64 dsid_clr_base1, u64 dsid_clr_base2, + u64 dsid_clr_base3, u32 dsid_clr_range0, + u32 dsid_clr_range1, u32 dsid_clr_range2, + u32 dsid_clr_range3) +{ + struct cmd_set_dsid_clr_req_base2 args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_DSID_CLR_REG_BASE2), + .dsid_clr_base0 = dsid_clr_base0, + .dsid_clr_base1 = dsid_clr_base1, + .dsid_clr_base2 = dsid_clr_base2, + .dsid_clr_base3 = dsid_clr_base3, + .dsid_clr_range0 = dsid_clr_range0, + .dsid_clr_range1 = dsid_clr_range1, + .dsid_clr_range2 = dsid_clr_range2, + .dsid_clr_range3 = dsid_clr_range3, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, + u64 clock_base, u8 clock_bit, u8 clock_size, + u64 bandwidth_scratch, u64 bandwidth_base, + u8 bandwidth_bit, u8 bandwidth_size) +{ + struct cmd_pmp_ctrl_set args = { + .opcode = CISP_OPCODE(CISP_CMD_PMP_CTRL_SET), + .clock_scratch = clock_scratch, + .clock_base = clock_base, + .clock_bit = clock_bit, + .clock_size = clock_size, + .clock_pad = 0, + .bandwidth_scratch = bandwidth_scratch, + .bandwidth_base = bandwidth_base, + .bandwidth_bit = bandwidth_bit, + .bandwidth_size = bandwidth_size, + .bandwidth_pad = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_fid_enter(struct apple_isp *isp) +{ + struct cmd_fid_enter args = { + .opcode = CISP_OPCODE(CISP_CMD_FID_ENTER), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_fid_exit(struct apple_isp *isp) +{ + struct cmd_fid_exit args = { + .opcode = CISP_OPCODE(CISP_CMD_FID_EXIT), + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_info *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_INFO_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_get(struct apple_isp *isp, u32 chan, u32 preset, + struct cmd_ch_camera_config *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_GET); + args->preset = preset; + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_camera_config *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_CURRENT_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, u32 preset) +{ + struct cmd_ch_camera_config_select args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CAMERA_CONFIG_SELECT), + .chan = chan, + .preset = preset, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_return args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RETURN), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, + u32 size) +{ + struct cmd_ch_set_file_load args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable) +{ + struct cmd_ch_sbs_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SBS_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, + u32 y2) +{ + struct cmd_ch_crop_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CROP_SET), + .chan = chan, + .x1 = x1, + .y1 = y1, + .x2 = x2, + .y2 = y2, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, + u32 height, u32 colorspace, u32 format) +{ + struct cmd_ch_output_config_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_OUTPUT_CONFIG_SET), + .chan = chan, + .width = width, + .height = height, + .colorspace = colorspace, + .format = format, + .unk_w0 = width, + .unk_w1 = width, + .unk_24 = 0, + .padding_rows = 0, + .unk_h0 = height, + .compress = 0, + .unk_w2 = width, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream) +{ + struct cmd_ch_preview_stream_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PREVIEW_STREAM_SET), + .chan = chan, + .stream = stream, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_als_disable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_ALS_DISABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_cnr_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_CNR_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, + u32 mode, u32 enable_chroma) +{ + struct cmd_ch_mbnr_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_MBNR_ENABLE), + .chan = chan, + .use_case = use_case, + .mode = mode, + .enable_chroma = enable_chroma, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_sif_pixel_format_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SIF_PIXEL_FORMAT_SET), + .chan = chan, + .format = 3, + .type = 1, + .compress = 0, + .unk_10 = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, + u32 mode) +{ + struct cmd_ch_buffer_recycle_mode_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RECYCLE_MODE_SET), + .chan = chan, + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_recycle_start args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_RECYCLE_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) +{ + struct cmd_ch_buffer_pool_config_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_CONFIG_SET), + .chan = chan, + .type = type, + .count = 16, + .meta_size0 = ISP_META_SIZE, + .meta_size1 = ISP_META_SIZE, + .data_blocks = 1, + .compress = 0, + }; + memset(args.zero, 0, sizeof(u32) * 0x1f); + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan) +{ + struct cmd_ch_buffer_pool_return args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_RETURN), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_start args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START), + .chan = chan, + .unk_c = 1, + .unk_10 = 0, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_motion_history_start args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_MOTION_HISTORY_START), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_motion_history_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_MOTION_HISTORY_STOP), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_enable(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_ENABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_temporal_filter_disable(struct apple_isp *isp, u32 chan) +{ + struct cmd_apple_ch_temporal_filter_disable args = { + .opcode = + CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_DISABLE), + .chan = chan, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_stability_set(struct apple_isp *isp, u32 chan, u32 stability) +{ + struct cmd_ch_ae_stability_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_STABILITY_SET), + .chan = chan, + .stability = stability, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_stability_to_stable_set(struct apple_isp *isp, u32 chan, + u32 stability) +{ + struct cmd_ch_ae_stability_to_stable_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_STABILITY_TO_STABLE_SET), + .chan = chan, + .stability = stability, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_max_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_ae_frame_rate_max_get *args) +{ + args->opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MAX_GET); + args->chan = chan; + return CISP_SEND_OUT(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_max_set(struct apple_isp *isp, u32 chan, + u32 framerate) +{ + struct cmd_ch_ae_frame_rate_max_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MAX_SET), + .chan = chan, + .framerate = framerate, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_ae_frame_rate_min_set(struct apple_isp *isp, u32 chan, + u32 framerate) +{ + struct cmd_ch_ae_frame_rate_min_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_AE_FRAME_RATE_MIN_SET), + .chan = chan, + .framerate = framerate, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_ae_fd_scene_metering_config_set(struct apple_isp *isp, + u32 chan) +{ + struct cmd_apple_ch_ae_fd_scene_metering_config_set args = { + .opcode = CISP_OPCODE( + CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET), + .chan = chan, + .unk_c = 0xb8, + .unk_10 = 0x2000200, + .unk_14 = 0x280800, + .unk_18 = 0xe10028, + .unk_1c = 0xa0399, + .unk_20 = 0x3cc02cc, + }; + return CISP_SEND_INOUT(isp, args); +} + +int isp_cmd_apple_ch_ae_metering_mode_set(struct apple_isp *isp, u32 chan, + u32 mode) +{ + struct cmd_apple_ch_ae_metering_mode_set args = { + .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_AE_METERING_MODE_SET), + .chan = chan, + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_apple_ch_ae_flicker_freq_update_current_set(struct apple_isp *isp, + u32 chan, u32 freq) +{ + struct cmd_apple_ch_ae_flicker_freq_update_current_set args = { + .opcode = CISP_OPCODE( + CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET), + .chan = chan, + .freq = freq, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_semantic_video_enable(struct apple_isp *isp, u32 chan, + u32 enable) +{ + struct cmd_ch_semantic_video_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable) +{ + struct cmd_ch_semantic_awb_enable args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SEMANTIC_AWB_ENABLE), + .chan = chan, + .enable = enable, + }; + return CISP_SEND_IN(isp, args); +} diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h new file mode 100644 index 00000000000000..dde6aad506c23e --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_CMD_H__ +#define __ISP_CMD_H__ + +#include "isp-drv.h" + +#define CISP_CMD_START 0x0000 +#define CISP_CMD_STOP 0x0001 +#define CISP_CMD_CONFIG_GET 0x0003 +#define CISP_CMD_PRINT_ENABLE 0x0004 +#define CISP_CMD_BUILDINFO 0x0006 +#define CISP_CMD_GET_BES_PARAM 0x000f +#define CISP_CMD_SET_ISP_PMU_BASE 0x0011 +#define CISP_CMD_PMP_CTRL_SET 0x001c +#define CISP_CMD_TRACE_ENABLE 0x001d +#define CISP_CMD_SUSPEND 0x0021 +#define CISP_CMD_FID_ENTER 0x0022 +#define CISP_CMD_FID_EXIT 0x0023 +#define CISP_CMD_FLICKER_SENSOR_SET 0x0024 +#define CISP_CMD_CH_START 0x0100 +#define CISP_CMD_CH_STOP 0x0101 +#define CISP_CMD_CH_BUFFER_RETURN 0x0104 +#define CISP_CMD_CH_CAMERA_CONFIG_CURRENT_GET 0x0105 +#define CISP_CMD_CH_CAMERA_CONFIG_GET 0x0106 +#define CISP_CMD_CH_CAMERA_CONFIG_SELECT 0x0107 +#define CISP_CMD_CH_INFO_GET 0x010d +#define CISP_CMD_CH_BUFFER_RECYCLE_MODE_SET 0x010e +#define CISP_CMD_CH_BUFFER_RECYCLE_START 0x010f +#define CISP_CMD_CH_BUFFER_RECYCLE_STOP 0x0110 +#define CISP_CMD_CH_SET_FILE_LOAD 0x0111 +#define CISP_CMD_CH_SIF_PIXEL_FORMAT_SET 0x0115 +#define CISP_CMD_CH_BUFFER_POOL_CONFIG_GET 0x0116 +#define CISP_CMD_CH_BUFFER_POOL_CONFIG_SET 0x0117 +#define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_GET 0x011a +#define CISP_CMD_CH_CAMERA_PIX_FREQUENCY_GET 0x011f +#define CISP_CMD_CH_LOCAL_RAW_BUFFER_ENABLE 0x0125 +#define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_TOTAL_GET 0x0133 +#define CISP_CMD_CH_SBS_ENABLE 0x013b +#define CISP_CMD_CH_LSC_POLYNOMIAL_COEFF_GET 0x0142 +#define CISP_CMD_CH_BUFFER_POOL_RETURN 0x015b +#define CISP_CMD_CH_CAMERA_AGILE_FREQ_ARRAY_CURRENT_GET 0x015e +#define CISP_CMD_CH_AE_START 0x0200 +#define CISP_CMD_CH_AE_STOP 0x0201 +#define CISP_CMD_CH_AE_FRAME_RATE_MAX_GET 0x0207 +#define CISP_CMD_CH_AE_FRAME_RATE_MAX_SET 0x0208 +#define CISP_CMD_CH_AE_FRAME_RATE_MIN_GET 0x0209 +#define CISP_CMD_CH_AE_FRAME_RATE_MIN_SET 0x020a +#define CISP_CMD_CH_AE_STABILITY_SET 0x021a +#define CISP_CMD_CH_AE_STABILITY_TO_STABLE_SET 0x0229 +#define CISP_CMD_CH_SENSOR_NVM_GET 0x0501 +#define CISP_CMD_CH_SENSOR_PERMODULE_LSC_INFO_GET 0x0507 +#define CISP_CMD_CH_SENSOR_PERMODULE_LSC_GRID_GET 0x0511 +#define CISP_CMD_CH_FOCUS_LIMITS_GET 0x0701 +#define CISP_CMD_CH_CROP_SET 0x0801 +#define CISP_CMD_CH_ALS_ENABLE 0x0a1c +#define CISP_CMD_CH_ALS_DISABLE 0x0a1d +#define CISP_CMD_CH_CNR_START 0x0a2f +#define CISP_CMD_CH_MBNR_ENABLE 0x0a3a +#define CISP_CMD_CH_OUTPUT_CONFIG_SET 0x0b01 +#define CISP_CMD_CH_PREVIEW_STREAM_SET 0x0b0d +#define CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE 0x0b17 +#define CISP_CMD_CH_SEMANTIC_AWB_ENABLE 0x0b18 +#define CISP_CMD_CH_FACE_DETECTION_START 0x0d00 +#define CISP_CMD_CH_FACE_DETECTION_CONFIG_GET 0x0d02 +#define CISP_CMD_CH_FACE_DETECTION_CONFIG_SET 0x0d03 +#define CISP_CMD_CH_FACE_DETECTION_ENABLE 0x0d05 +#define CISP_CMD_CH_FID_START 0x3000 +#define CISP_CMD_CH_FID_STOP 0x3001 +#define CISP_CMD_IPC_ENDPOINT_SET2 0x300c +#define CISP_CMD_IPC_ENDPOINT_UNSET2 0x300d +#define CISP_CMD_SET_DSID_CLR_REG_BASE2 0x3204 +#define CISP_CMD_APPLE_CH_AE_METERING_MODE_SET 0x8206 +#define CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET 0x820e +#define CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET 0x8212 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START 0xc100 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_STOP 0xc101 +#define CISP_CMD_APPLE_CH_MOTION_HISTORY_START 0xc102 +#define CISP_CMD_APPLE_CH_MOTION_HISTORY_STOP 0xc103 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_ENABLE 0xc113 +#define CISP_CMD_APPLE_CH_TEMPORAL_FILTER_DISABLE 0xc114 + +#define CISP_POOL_TYPE_META 0x0 +#define CISP_POOL_TYPE_RENDERED 0x1 +#define CISP_POOL_TYPE_FD 0x2 +#define CISP_POOL_TYPE_RAW 0x3 +#define CISP_POOL_TYPE_STAT 0x4 +#define CISP_POOL_TYPE_META_CAPTURE 0x8 + +#define CISP_COLORSPACE_REC709 0x1 +#define CISP_OUTPUT_FORMAT_NV12 0x0 +#define CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY 0x1 + +struct cmd_start { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_start) == 0xc); + +struct cmd_suspend { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_suspend) == 0x8); + +struct cmd_print_enable { + u64 opcode; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_print_enable) == 0xc); + +struct cmd_trace_enable { + u64 opcode; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_trace_enable) == 0xc); + +struct cmd_config_get { + u64 opcode; + u32 timestamp_freq; + u32 num_channels; + u32 unk_10; + u32 unk_14; + u32 unk_18; +} __packed; +static_assert(sizeof(struct cmd_config_get) == 0x1c); + +struct cmd_set_isp_pmu_base { + u64 opcode; + u64 pmu_base; +} __packed; +static_assert(sizeof(struct cmd_set_isp_pmu_base) == 0x10); + +struct cmd_set_dsid_clr_req_base2 { + u64 opcode; + u64 dsid_clr_base0; + u64 dsid_clr_base1; + u64 dsid_clr_base2; + u64 dsid_clr_base3; + u32 dsid_clr_range0; + u32 dsid_clr_range1; + u32 dsid_clr_range2; + u32 dsid_clr_range3; +} __packed; +static_assert(sizeof(struct cmd_set_dsid_clr_req_base2) == 0x38); + +struct cmd_pmp_ctrl_set { + u64 opcode; + u64 clock_scratch; + u64 clock_base; + u8 clock_bit; + u8 clock_size; + u16 clock_pad; + u64 bandwidth_scratch; + u64 bandwidth_base; + u8 bandwidth_bit; + u8 bandwidth_size; + u16 bandwidth_pad; +} __packed; +static_assert(sizeof(struct cmd_pmp_ctrl_set) == 0x30); + +struct cmd_fid_enter { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_fid_enter) == 0x8); + +struct cmd_fid_exit { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_fid_exit) == 0x8); + +int isp_cmd_start(struct apple_isp *isp, u32 mode); +int isp_cmd_suspend(struct apple_isp *isp); +int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); +int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); +int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args); +int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base); +int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, + u64 dsid_clr_base1, u64 dsid_clr_base2, + u64 dsid_clr_base3, u32 dsid_clr_range0, + u32 dsid_clr_range1, u32 dsid_clr_range2, + u32 dsid_clr_range3); +int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, + u64 clock_base, u8 clock_bit, u8 clock_size, + u64 bandwidth_scratch, u64 bandwidth_base, + u8 bandwidth_bit, u8 bandwidth_size); +int isp_cmd_fid_enter(struct apple_isp *isp); +int isp_cmd_fid_exit(struct apple_isp *isp); + +struct cmd_ch_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_start) == 0xc); + +struct cmd_ch_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_stop) == 0xc); + +struct cmd_ch_info { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10[4]; + u32 version; + u32 unk_24[3]; + u32 unk_30[12]; + u32 num_presets; + u32 unk_64[7]; + u32 unk_80[6]; + u32 unk_98_freq; + u16 pad_9c; + char module_sn[20]; + u16 pad_b0; + u32 unk_b4[25]; +} __packed; +static_assert(sizeof(struct cmd_ch_info) == 0x118); + +struct cmd_ch_camera_config { + u64 opcode; + u32 chan; + u32 preset; + u16 in_width; + u16 in_height; + u16 out_width; + u16 out_height; + u32 unk[49]; +} __packed; +static_assert(sizeof(struct cmd_ch_camera_config) == 0xdc); + +struct cmd_ch_camera_config_select { + u64 opcode; + u32 chan; + u32 preset; +} __packed; +static_assert(sizeof(struct cmd_ch_camera_config_select) == 0x10); + +struct cmd_ch_set_file_load { + u64 opcode; + u32 chan; + u32 addr; + u32 size; +} __packed; +static_assert(sizeof(struct cmd_ch_set_file_load) == 0x14); + +struct cmd_ch_buffer_return { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_return) == 0xc); + +struct cmd_ch_sbs_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_sbs_enable) == 0x10); + +struct cmd_ch_crop_set { + u64 opcode; + u32 chan; + u32 x1; + u32 y1; + u32 x2; + u32 y2; +} __packed; +static_assert(sizeof(struct cmd_ch_crop_set) == 0x1c); + +struct cmd_ch_output_config_set { + u64 opcode; + u32 chan; + u32 width; + u32 height; + u32 colorspace; + u32 format; + u32 unk_w0; + u32 unk_w1; + u32 unk_24; + u32 padding_rows; + u32 unk_h0; + u32 compress; + u32 unk_w2; +} __packed; +static_assert(sizeof(struct cmd_ch_output_config_set) == 0x38); + +struct cmd_ch_preview_stream_set { + u64 opcode; + u32 chan; + u32 stream; +} __packed; +static_assert(sizeof(struct cmd_ch_preview_stream_set) == 0x10); + +struct cmd_ch_als_disable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_als_disable) == 0xc); + +struct cmd_ch_cnr_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_cnr_start) == 0xc); + +struct cmd_ch_mbnr_enable { + u64 opcode; + u32 chan; + u32 use_case; + u32 mode; + u32 enable_chroma; +} __packed; +static_assert(sizeof(struct cmd_ch_mbnr_enable) == 0x18); + +struct cmd_ch_sif_pixel_format_set { + u64 opcode; + u32 chan; + u8 format; + u8 type; + u16 compress; + u32 unk_10; +} __packed; +static_assert(sizeof(struct cmd_ch_sif_pixel_format_set) == 0x14); + +int isp_cmd_ch_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_info *args); +int isp_cmd_ch_camera_config_get(struct apple_isp *isp, u32 chan, u32 preset, + struct cmd_ch_camera_config *args); +int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_camera_config *args); +int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, + u32 preset); +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, + u32 size); +int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable); +int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, + u32 y2); +int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, + u32 height, u32 colorspace, u32 format); +int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream); +int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, + u32 mode, u32 enable_chroma); +int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan); + +struct cmd_ch_buffer_recycle_mode_set { + u64 opcode; + u32 chan; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_recycle_mode_set) == 0x10); + +struct cmd_ch_buffer_recycle_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_recycle_start) == 0xc); + +struct cmd_ch_buffer_pool_config_set { + u64 opcode; + u32 chan; + u16 type; + u16 count; + u32 meta_size0; + u32 meta_size1; + u32 zero[0x1f]; + u32 data_blocks; + u32 compress; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_pool_config_set) == 0x9c); + +struct cmd_ch_buffer_pool_return { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_ch_buffer_pool_return) == 0xc); + +int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, + u32 mode); +int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, + u16 type); +int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan); + +struct cmd_apple_ch_temporal_filter_start { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_start) == 0x14); + +struct cmd_apple_ch_temporal_filter_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_stop) == 0xc); + +struct cmd_apple_ch_motion_history_start { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_motion_history_start) == 0xc); + +struct cmd_apple_ch_motion_history_stop { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_motion_history_stop) == 0xc); + +struct cmd_apple_ch_temporal_filter_enable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_enable) == 0xc); + +struct cmd_apple_ch_temporal_filter_disable { + u64 opcode; + u32 chan; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_temporal_filter_disable) == 0xc); + +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_enable(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_disable(struct apple_isp *isp, u32 chan); + +struct cmd_ch_ae_stability_set { + u64 opcode; + u32 chan; + u32 stability; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_stability_set) == 0x10); + +struct cmd_ch_ae_stability_to_stable_set { + u64 opcode; + u32 chan; + u32 stability; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_stability_to_stable_set) == 0x10); + +struct cmd_ch_ae_frame_rate_max_get { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_max_get) == 0x10); + +struct cmd_ch_ae_frame_rate_max_set { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_max_set) == 0x10); + +struct cmd_ch_ae_frame_rate_min_set { + u64 opcode; + u32 chan; + u32 framerate; +} __packed; +static_assert(sizeof(struct cmd_ch_ae_frame_rate_min_set) == 0x10); + +struct cmd_apple_ch_ae_fd_scene_metering_config_set { + u64 opcode; + u32 chan; + u32 unk_c; + u32 unk_10; + u32 unk_14; + u32 unk_18; + u32 unk_1c; + u32 unk_20; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_fd_scene_metering_config_set) == + 0x24); + +struct cmd_apple_ch_ae_metering_mode_set { + u64 opcode; + u32 chan; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_metering_mode_set) == 0x10); + +struct cmd_apple_ch_ae_flicker_freq_update_current_set { + u64 opcode; + u32 chan; + u32 freq; +} __packed; +static_assert(sizeof(struct cmd_apple_ch_ae_flicker_freq_update_current_set) == + 0x10); + +int isp_cmd_ch_ae_stability_set(struct apple_isp *isp, u32 chan, u32 stability); +int isp_cmd_ch_ae_stability_to_stable_set(struct apple_isp *isp, u32 chan, + u32 stability); +int isp_cmd_ch_ae_frame_rate_max_get(struct apple_isp *isp, u32 chan, + struct cmd_ch_ae_frame_rate_max_get *args); +int isp_cmd_ch_ae_frame_rate_max_set(struct apple_isp *isp, u32 chan, + u32 framerate); +int isp_cmd_ch_ae_frame_rate_min_set(struct apple_isp *isp, u32 chan, + u32 framerate); +int isp_cmd_apple_ch_ae_fd_scene_metering_config_set(struct apple_isp *isp, + u32 chan); +int isp_cmd_apple_ch_ae_metering_mode_set(struct apple_isp *isp, u32 chan, + u32 mode); +int isp_cmd_apple_ch_ae_flicker_freq_update_current_set(struct apple_isp *isp, + u32 chan, u32 freq); + +struct cmd_ch_semantic_video_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_semantic_video_enable) == 0x10); + +struct cmd_ch_semantic_awb_enable { + u64 opcode; + u32 chan; + u32 enable; +} __packed; +static_assert(sizeof(struct cmd_ch_semantic_awb_enable) == 0x10); + +int isp_cmd_ch_semantic_video_enable(struct apple_isp *isp, u32 chan, + u32 enable); +int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable); + +#endif /* __ISP_CMD_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c new file mode 100644 index 00000000000000..e1f7842ed09b36 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Apple Image Signal Processor driver + * + * Copyright (C) 2023 The Asahi Linux Contributors + * + * Based on aspeed/aspeed-video.c + * Copyright 2020 IBM Corp. + * Copyright (c) 2019-2020 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "isp-cam.h" +#include "isp-iommu.h" +#include "isp-v4l2.h" + +static void apple_isp_detach_genpd(struct apple_isp *isp) +{ + if (isp->pd_count <= 1) + return; + + for (int i = isp->pd_count - 1; i >= 0; i--) { + if (isp->pd_link[i]) + device_link_del(isp->pd_link[i]); + if (!IS_ERR_OR_NULL(isp->pd_dev[i])) + dev_pm_domain_detach(isp->pd_dev[i], true); + } + + return; +} + +static int apple_isp_attach_genpd(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + + isp->pd_count = of_count_phandle_with_args( + dev->of_node, "power-domains", "#power-domain-cells"); + if (isp->pd_count <= 1) + return 0; + + isp->pd_dev = devm_kcalloc(dev, isp->pd_count, sizeof(*isp->pd_dev), + GFP_KERNEL); + if (!isp->pd_dev) + return -ENOMEM; + + isp->pd_link = devm_kcalloc(dev, isp->pd_count, sizeof(*isp->pd_link), + GFP_KERNEL); + if (!isp->pd_link) + return -ENOMEM; + + for (int i = 0; i < isp->pd_count; i++) { + isp->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); + if (IS_ERR(isp->pd_dev[i])) { + apple_isp_detach_genpd(isp); + return PTR_ERR(isp->pd_dev[i]); + } + + isp->pd_link[i] = + device_link_add(dev, isp->pd_dev[i], + DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | + DL_FLAG_RPM_ACTIVE); + if (!isp->pd_link[i]) { + apple_isp_detach_genpd(isp); + return -EINVAL; + } + } + + return 0; +} + +static int apple_isp_init_iommu(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + struct isp_firmware *fw = &isp->fw; + u64 heap_base, heap_size, vm_size; + int err; + int i = 0; + + isp->domain = iommu_get_domain_for_dev(isp->dev); + if (!isp->domain) + return -EPROBE_DEFER; + isp->shift = __ffs(isp->domain->pgsize_bitmap); + + err = of_property_read_u64(dev->of_node, "apple,isp-heap-base", + &heap_base); + if (err) { + dev_err(dev, "failed to read 'apple,isp-heap-base': %d\n", err); + return err; + } + + err = of_property_read_u64(dev->of_node, "apple,isp-heap-size", + &heap_size); + if (err) { + dev_err(dev, "failed to read 'apple,isp-heap-size': %d\n", err); + return err; + } + + err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", + &vm_size); + if (err) { + dev_err(dev, "failed to read 'apple,dart-vm-size': %d\n", err); + return err; + } + + drm_mm_init(&isp->iovad, heap_base, vm_size - heap_base); + + /* Allocate read-only coprocessor private heap */ + fw->heap = isp_alloc_surface(isp, heap_size); + if (!fw->heap) { + drm_mm_takedown(&isp->iovad); + err = -ENOMEM; + return err; + } + + apple_isp_iommu_sync_ttbr(isp); + + return 0; +} + +static void apple_isp_free_iommu(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->fw.heap); + drm_mm_takedown(&isp->iovad); +} + +static int apple_isp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apple_isp *isp; + struct resource *res; + int err; + + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); + if (!isp) + return -ENOMEM; + + isp->dev = dev; + isp->hw = of_device_get_match_data(dev); + platform_set_drvdata(pdev, isp); + dev_set_drvdata(dev, isp); + + err = apple_isp_attach_genpd(isp); + if (err) { + dev_err(dev, "failed to attatch power domains\n"); + return err; + } + + isp->asc = devm_platform_ioremap_resource_byname(pdev, "asc"); + if (IS_ERR(isp->asc)) { + err = PTR_ERR(isp->asc); + goto detach_genpd; + } + + isp->core = devm_platform_ioremap_resource_byname(pdev, "core"); + if (IS_ERR(isp->core)) { + err = PTR_ERR(isp->core); + goto detach_genpd; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dart0"); + if (!res) { + err = -ENODEV; + goto detach_genpd; + } + + /* Simply ioremap since it's a shared register zone */ + isp->dart0 = devm_ioremap(dev, res->start, resource_size(res)); + if (IS_ERR(isp->dart0)) { + err = PTR_ERR(isp->dart0); + goto detach_genpd; + } + + isp->dart1 = devm_platform_ioremap_resource_byname(pdev, "dart1"); + if (IS_ERR(isp->dart1)) { + err = PTR_ERR(isp->dart1); + goto detach_genpd; + } + + isp->dart2 = devm_platform_ioremap_resource_byname(pdev, "dart2"); + if (IS_ERR(isp->dart2)) { + err = PTR_ERR(isp->dart2); + goto detach_genpd; + } + + isp->irq = platform_get_irq(pdev, 0); + if (isp->irq < 0) { + err = isp->irq; + goto detach_genpd; + } + if (!isp->irq) { + err = -ENODEV; + goto detach_genpd; + } + + mutex_init(&isp->iovad_lock); + mutex_init(&isp->video_lock); + spin_lock_init(&isp->buf_lock); + init_waitqueue_head(&isp->wait); + INIT_LIST_HEAD(&isp->gc); + INIT_LIST_HEAD(&isp->buffers); + isp->wq = alloc_workqueue("apple-isp-wq", WQ_UNBOUND, 0); + if (!isp->wq) { + dev_err(dev, "failed to create workqueue\n"); + err = -ENOMEM; + goto detach_genpd; + } + + err = apple_isp_init_iommu(isp); + if (err) { + dev_err(dev, "failed to init iommu: %d\n", err); + goto destroy_wq; + } + + pm_runtime_enable(dev); + + err = apple_isp_detect_camera(isp); + if (err) { + dev_err(dev, "failed to detect camera: %d\n", err); + goto free_iommu; + } + + err = apple_isp_setup_video(isp); + if (err) { + dev_err(dev, "failed to register video device: %d\n", err); + goto free_iommu; + } + + dev_info(dev, "apple-isp probe!\n"); + + return 0; + +free_iommu: + pm_runtime_disable(dev); + apple_isp_free_iommu(isp); +destroy_wq: + destroy_workqueue(isp->wq); +detach_genpd: + apple_isp_detach_genpd(isp); + return err; +} + +static int apple_isp_remove(struct platform_device *pdev) +{ + struct apple_isp *isp = platform_get_drvdata(pdev); + + apple_isp_remove_video(isp); + pm_runtime_disable(isp->dev); + apple_isp_free_iommu(isp); + destroy_workqueue(isp->wq); + apple_isp_detach_genpd(isp); + return 0; +} + +/* T8020/T6000 registers */ +#define DART_T8020_STREAM_COMMAND 0x20 +#define DART_T8020_STREAM_SELECT 0x34 +#define DART_T8020_TTBR 0x200 +#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) + +static const struct apple_isp_hw apple_isp_hw_t8103 = { + .pmu_base = 0x23b704000, + + .dsid_clr_base0 = 0x200014000, + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x23b738010, + .clock_base = 0x23bc3c000, + .clock_bit = 0x1, + .clock_size = 0x4, + .bandwidth_scratch = 0x23b73800c, + .bandwidth_base = 0x23bc3c000, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x4, + + .stream_command = DART_T8020_STREAM_COMMAND, + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + +static const struct of_device_id apple_isp_of_match[] = { + { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + {}, +}; +MODULE_DEVICE_TABLE(of, apple_isp_of_match); + +static __maybe_unused int apple_isp_suspend(struct device *dev) +{ + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_iommu_invalidate_tlb(isp); + + return 0; +} + +static __maybe_unused int apple_isp_resume(struct device *dev) +{ + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_iommu_sync_ttbr(isp); + + return 0; +} +DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); + +static struct platform_driver apple_isp_driver = { + .driver = { + .name = "apple-isp", + .of_match_table = apple_isp_of_match, + .pm = pm_ptr(&apple_isp_pm_ops), + }, + .probe = apple_isp_probe, + .remove = apple_isp_remove, +}; +module_platform_driver(apple_isp_driver); + +MODULE_AUTHOR("Eileen Yoon "); +MODULE_DESCRIPTION("Apple ISP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h new file mode 100644 index 00000000000000..5db64dcc844863 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_DRV_H__ +#define __ISP_DRV_H__ + +#include +#include +#include +#include + +#include +#include +#include +#include + +/* #define APPLE_ISP_DEBUG */ +#define APPLE_ISP_DEVICE_NAME "apple-isp" + +#define ISP_MAX_CHANNELS 6 +#define ISP_IPC_MESSAGE_SIZE 64 +#define ISP_IPC_FLAG_ACK 0x1 +#define ISP_META_SIZE 0x4640 + +struct isp_surf { + struct drm_mm_node *mm; + struct list_head head; + u64 size; + u32 num_pages; + struct page **pages; + struct sg_table sgt; + dma_addr_t iova; + void *virt; + refcount_t refcount; + bool gc; +}; + +struct isp_message { + u64 arg0; + u64 arg1; + u64 arg2; + u64 arg3; + u64 arg4; + u64 arg5; + u64 arg6; + u64 arg7; +} __packed; +static_assert(sizeof(struct isp_message) == ISP_IPC_MESSAGE_SIZE); + +struct isp_channel { + char *name; + u32 type; + u32 src; + u32 num; + u64 size; + dma_addr_t iova; + u32 doorbell; + u32 cursor; + spinlock_t lock; + struct isp_message req; + struct isp_message rsp; + const struct isp_chan_ops *ops; +}; + +struct apple_isp_hw { + u64 pmu_base; + + u64 dsid_clr_base0; + u64 dsid_clr_base1; + u64 dsid_clr_base2; + u64 dsid_clr_base3; + u32 dsid_clr_range0; + u32 dsid_clr_range1; + u32 dsid_clr_range2; + u32 dsid_clr_range3; + + u64 clock_scratch; + u64 clock_base; + u8 clock_bit; + u8 clock_size; + u64 bandwidth_scratch; + u64 bandwidth_base; + u8 bandwidth_bit; + u8 bandwidth_size; + + u32 stream_command; + u32 stream_select; + u32 ttbr; + u32 stream_command_invalidate; +}; + +struct isp_resv { + phys_addr_t phys; + dma_addr_t iova; + u64 size; +}; + +enum isp_sensor_id { + ISP_IMX248_1820_01, + ISP_IMX248_1822_02, + ISP_IMX343_5221_02, + ISP_IMX354_9251_02, + ISP_IMX356_4820_01, + ISP_IMX356_4820_02, + ISP_IMX364_8720_01, + ISP_IMX364_8723_01, + ISP_IMX372_3820_01, + ISP_IMX372_3820_02, + ISP_IMX372_3820_11, + ISP_IMX372_3820_12, + ISP_IMX405_9720_01, + ISP_IMX405_9721_01, + ISP_IMX405_9723_01, + ISP_IMX414_2520_01, + ISP_IMX503_7820_01, + ISP_IMX503_7820_02, + ISP_IMX505_3921_01, + ISP_IMX514_2820_01, + ISP_IMX514_2820_02, + ISP_IMX514_2820_03, + ISP_IMX514_2820_04, + ISP_IMX558_1921_01, + ISP_IMX558_1922_02, + ISP_IMX603_7920_01, + ISP_IMX603_7920_02, + ISP_IMX603_7921_01, + ISP_IMX613_4920_01, + ISP_IMX613_4920_02, + ISP_IMX614_2921_01, + ISP_IMX614_2921_02, + ISP_IMX614_2922_02, + ISP_IMX633_3622_01, + ISP_IMX703_7721_01, + ISP_IMX703_7722_01, + ISP_IMX713_4721_01, + ISP_IMX713_4722_01, + ISP_IMX714_2022_01, + ISP_IMX772_3721_01, + ISP_IMX772_3721_11, + ISP_IMX772_3722_01, + ISP_IMX772_3723_01, + ISP_IMX814_2123_01, + ISP_IMX853_7622_01, + ISP_IMX913_7523_01, + ISP_VD56G0_6221_01, + ISP_VD56G0_6222_01, +}; + +struct isp_format { + enum isp_sensor_id id; + u32 version; + u32 num_presets; + u32 preset; + u32 width; + u32 height; + u32 x1; + u32 y1; + u32 x2; + u32 y2; + unsigned int num_planes; + size_t plane_size[VB2_MAX_PLANES]; + size_t total_size; +}; + +struct apple_isp { + struct device *dev; + const struct apple_isp_hw *hw; + + int num_channels; + struct isp_format fmts[ISP_MAX_CHANNELS]; + unsigned int current_ch; + + struct video_device vdev; + struct media_device mdev; + struct v4l2_device v4l2_dev; + struct vb2_queue vbq; + struct mutex video_lock; + unsigned int sequence; + bool multiplanar; + + int pd_count; + struct device **pd_dev; + struct device_link **pd_link; + + int irq; + + void __iomem *asc; + void __iomem *core; + void __iomem *dart0; + void __iomem *dart1; + void __iomem *dart2; + + struct iommu_domain *domain; + unsigned long shift; + struct drm_mm iovad; /* TODO iova.c can't allocate bottom-up */ + struct mutex iovad_lock; + + struct isp_firmware { + struct isp_surf *heap; + } fw; + + struct isp_surf *ipc_surf; + struct isp_surf *extra_surf; + struct isp_surf *data_surf; + struct list_head gc; + struct workqueue_struct *wq; + + int num_ipc_chans; + struct isp_channel **ipc_chans; + struct isp_channel *chan_tm; /* TERMINAL */ + struct isp_channel *chan_io; /* IO */ + struct isp_channel *chan_dg; /* DEBUG */ + struct isp_channel *chan_bh; /* BUF_H2T */ + struct isp_channel *chan_bt; /* BUF_T2H */ + struct isp_channel *chan_sm; /* SHAREDMALLOC */ + struct isp_channel *chan_it; /* IO_T2H */ + + wait_queue_head_t wait; + dma_addr_t cmd_iova; + + unsigned long state; + spinlock_t buf_lock; + struct list_head buffers; +}; + +struct isp_chan_ops { + int (*handle)(struct apple_isp *isp, struct isp_channel *chan); +}; + +struct isp_buffer { + struct vb2_v4l2_buffer vb; + struct list_head link; + struct isp_surf surfs[VB2_MAX_PLANES]; + struct isp_surf *meta; +}; + +#define to_isp_buffer(x) container_of((x), struct isp_buffer, vb) + +enum { + ISP_STATE_STREAMING, + ISP_STATE_LOGGING, +}; + +#ifdef APPLE_ISP_DEBUG +#define isp_dbg(isp, fmt, ...) \ + dev_info((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) +#else +#define isp_dbg(isp, fmt, ...) \ + dev_dbg((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) +#endif + +#define isp_err(isp, fmt, ...) \ + dev_err((isp)->dev, "[%s] " fmt, __func__, ##__VA_ARGS__) + +#define isp_get_format(isp, ch) (&(isp)->fmts[(ch)]) +#define isp_get_current_format(isp) (isp_get_format(isp, isp->current_ch)) + +#endif /* __ISP_DRV_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c new file mode 100644 index 00000000000000..3d1e961a1cc262 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include +#include + +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-regs.h" + +#define ISP_FIRMWARE_MDELAY 1 +#define ISP_FIRMWARE_MAX_TRIES 1000 + +#define ISP_FIRMWARE_BOOTARGS_SIZE 0x180 +#define ISP_FIRMWARE_IPC_SIZE 0x1c000 +#define ISP_FIRMWARE_DATA_SIZE 0x28000 + +static inline u32 isp_asc_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->asc + reg); +} + +static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->asc + reg); +} + +struct isp_firmware_bootargs { + u32 pad_0[2]; + u64 ipc_iova; + u64 unk_size; + u64 unk_inv; + u64 extra_iova; + u64 extra_size; + u32 unk4; + u32 pad_40[7]; + u32 ipc_size; + u32 pad_60[5]; + u32 unk5; + u32 pad_7c[13]; + u32 pad_b0; + u32 unk7; + u32 pad_b8[5]; + u32 unk_iova1; + u32 pad_c0[47]; + u32 unk9; +} __packed; +static_assert(sizeof(struct isp_firmware_bootargs) == + ISP_FIRMWARE_BOOTARGS_SIZE); + +struct isp_chan_desc { + char name[64]; + u32 type; + u32 src; + u32 num; + u32 pad; + u64 iova; + u32 padding[0x2a]; +} __packed; +static_assert(sizeof(struct isp_chan_desc) == 0x100); + +static const struct isp_chan_ops tm_ops = { + .handle = ipc_tm_handle, +}; + +static const struct isp_chan_ops sm_ops = { + .handle = ipc_sm_handle, +}; + +static const struct isp_chan_ops bt_ops = { + .handle = ipc_bt_handle, +}; + +static irqreturn_t apple_isp_isr(int irq, void *dev) +{ + struct apple_isp *isp = dev; + + isp_core_write32(isp, ISP_CORE_IRQ_ACK, + isp_core_read32(isp, ISP_CORE_IRQ_INTERRUPT)); + + wake_up_interruptible_all(&isp->wait); + + ipc_chan_handle(isp, isp->chan_sm); + wake_up_interruptible_all(&isp->wait); /* Some commands depend on sm */ + + ipc_chan_handle(isp, isp->chan_tm); + + ipc_chan_handle(isp, isp->chan_bt); + wake_up_interruptible_all(&isp->wait); + + return IRQ_HANDLED; +} + +static void isp_disable_irq(struct apple_isp *isp) +{ + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + free_irq(isp->irq, isp); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0xfeedbabe); /* real funny */ +} + +static int isp_enable_irq(struct apple_isp *isp) +{ + int err; + + err = request_irq(isp->irq, apple_isp_isr, 0, "apple-isp", isp); + if (err < 0) { + isp_err(isp, "failed to request IRQ#%u (%d)\n", isp->irq, err); + return err; + } + + isp_dbg(isp, "about to enable interrupts...\n"); + + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0xf); + + return 0; +} + +static int isp_coproc_ready(struct apple_isp *isp) +{ + int retries; + u32 status; + + isp_asc_write32(isp, ISP_ASC_EDPRCR, 0x2); + + isp_asc_write32(isp, ISP_ASC_PMGR_0, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_1, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_2, 0xff00ff); + isp_asc_write32(isp, ISP_ASC_PMGR_3, 0xff00ff); + + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_0, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_1, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_2, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_3, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_4, 0xffffffff); + isp_asc_write32(isp, ISP_ASC_IRQ_MASK_5, 0xffffffff); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + status = isp_asc_read32(isp, ISP_ASC_STATUS); + if (!((status & 0x3) == 0)) { + isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", + retries, status); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, "coproc NOT in WFI (status: 0x%x)\n", status); + return -ENODEV; + } + + return 0; +} + +static void isp_firmware_shutdown_stage1(struct apple_isp *isp) +{ + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); +} + +static int isp_firmware_boot_stage1(struct apple_isp *isp) +{ + int err, retries; + + err = isp_coproc_ready(isp); + if (err < 0) + return err; + + isp_core_write32(isp, ISP_CORE_CLOCK_EN, 0x1); + + isp_core_write32(isp, ISP_CORE_GPIO_0, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_2, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_3, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_4, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_5, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_6, 0x0); + isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + + isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); + isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); + + /* Wait for ISP_CORE_GPIO_7 to 0x0 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + if (val == 0x8042006) { + isp_dbg(isp, + "got first magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received first magic number from firmware\n"); + return -ENODEV; + } + + return 0; +} + +static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->data_surf); + isp_free_surface(isp, isp->extra_surf); + isp_free_surface(isp, isp->ipc_surf); +} + +static int isp_firmware_boot_stage2(struct apple_isp *isp) +{ + struct isp_firmware_bootargs args; + dma_addr_t args_iova; + int err, retries; + + u32 num_ipc_chans = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 args_offset = isp_core_read32(isp, ISP_CORE_GPIO_1); + u32 extra_size = isp_core_read32(isp, ISP_CORE_GPIO_3); + isp->num_ipc_chans = num_ipc_chans; + + if (!isp->num_ipc_chans) { + dev_err(isp->dev, "No IPC channels found\n"); + return -ENODEV; + } + + if (isp->num_ipc_chans != 7) + dev_warn(isp->dev, "unexpected channel count (%d)\n", + num_ipc_chans); + + isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); + if (!isp->ipc_surf) { + isp_err(isp, "failed to alloc surface for ipc\n"); + return -ENOMEM; + } + + isp->extra_surf = isp_alloc_surface_vmap(isp, extra_size); + if (!isp->extra_surf) { + isp_err(isp, "failed to alloc surface for extra heap\n"); + goto free_ipc; + } + + isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); + if (!isp->data_surf) { + isp_err(isp, "failed to alloc surface for data files\n"); + goto free_extra; + } + + args_iova = isp->ipc_surf->iova + args_offset + 0x40; + isp->cmd_iova = args_iova + sizeof(args) + 0x40; + + memset(&args, 0, sizeof(args)); + args.ipc_iova = isp->ipc_surf->iova; + args.ipc_size = isp->ipc_surf->size; + args.unk_size = 0x1800000; + args.unk_inv = 0x10000000 - args.unk_size; + args.extra_iova = isp->extra_surf->iova; + args.extra_size = isp->extra_surf->size; + args.unk4 = 0x1; + args.unk5 = 0x40; + args.unk7 = 0x1; + args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; + args.unk9 = 0x3; + isp_iowrite(isp, args_iova, &args, sizeof(args)); + + isp_core_write32(isp, ISP_CORE_GPIO_0, args_iova); + isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + + /* Wait for ISP_CORE_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_7, 0xf7fbdff9); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + if (val == 0x8042006) { + isp_dbg(isp, + "got second magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received second magic number from firmware\n"); + err = -ENODEV; + goto free_file; + } + + return 0; + +free_file: + isp_free_surface(isp, isp->data_surf); +free_extra: + isp_free_surface(isp, isp->extra_surf); +free_ipc: + isp_free_surface(isp, isp->ipc_surf); + return err; +} + +static inline struct isp_channel *isp_get_chan_index(struct apple_isp *isp, + const char *name) +{ + for (int i = 0; i < isp->num_ipc_chans; i++) { + if (!strcasecmp(isp->ipc_chans[i]->name, name)) + return isp->ipc_chans[i]; + } + return NULL; +} + +static void isp_free_channel_info(struct apple_isp *isp) +{ + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_channel *chan = isp->ipc_chans[i]; + if (!chan) + continue; + kfree(chan->name); + kfree(chan); + isp->ipc_chans[i] = NULL; + } + kfree(isp->ipc_chans); + isp->ipc_chans = NULL; +} + +static int isp_fill_channel_info(struct apple_isp *isp) +{ + u32 table_iova = isp_core_read32(isp, ISP_CORE_GPIO_0); + + isp->ipc_chans = kcalloc(isp->num_ipc_chans, + sizeof(struct isp_channel *), GFP_KERNEL); + if (!isp->ipc_chans) + goto out; + + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_chan_desc desc; + dma_addr_t desc_iova = table_iova + (i * sizeof(desc)); + struct isp_channel *chan = + kzalloc(sizeof(struct isp_channel), GFP_KERNEL); + if (!chan) + goto out; + isp->ipc_chans[i] = chan; + + isp_ioread(isp, desc_iova, &desc, sizeof(desc)); + chan->name = kstrdup(desc.name, GFP_KERNEL); + chan->type = desc.type; + chan->src = desc.src; + chan->doorbell = 1 << chan->src; + chan->num = desc.num; + chan->size = desc.num * ISP_IPC_MESSAGE_SIZE; + chan->iova = desc.iova; + chan->cursor = 0; + spin_lock_init(&chan->lock); + + if ((chan->type != ISP_IPC_CHAN_TYPE_COMMAND) && + (chan->type != ISP_IPC_CHAN_TYPE_REPLY) && + (chan->type != ISP_IPC_CHAN_TYPE_REPORT)) { + isp_err(isp, "invalid ipc chan type (%d)\n", + chan->type); + goto out; + } + + isp_dbg(isp, "chan: %s type: %d src: %d num: %d iova: 0x%llx\n", + chan->name, chan->type, chan->src, chan->num, + chan->iova); + } + + isp->chan_tm = isp_get_chan_index(isp, "TERMINAL"); + isp->chan_io = isp_get_chan_index(isp, "IO"); + isp->chan_dg = isp_get_chan_index(isp, "DEBUG"); + isp->chan_bh = isp_get_chan_index(isp, "BUF_H2T"); + isp->chan_bt = isp_get_chan_index(isp, "BUF_T2H"); + isp->chan_sm = isp_get_chan_index(isp, "SHAREDMALLOC"); + isp->chan_it = isp_get_chan_index(isp, "IO_T2H"); + + if (!isp->chan_tm || !isp->chan_io || !isp->chan_dg || !isp->chan_bh || + !isp->chan_bt || !isp->chan_sm || !isp->chan_it) { + isp_err(isp, "did not find all of the required ipc chans\n"); + goto out; + } + + isp->chan_tm->ops = &tm_ops; + isp->chan_sm->ops = &sm_ops; + isp->chan_bt->ops = &bt_ops; + + return 0; +out: + isp_free_channel_info(isp); + return -ENOMEM; +} + +static void isp_firmware_shutdown_stage3(struct apple_isp *isp) +{ + isp_free_channel_info(isp); +} + +static int isp_firmware_boot_stage3(struct apple_isp *isp) +{ + int err, retries; + + err = isp_fill_channel_info(isp); + if (err < 0) + return err; + + /* Mask the command channels to prepare for submission */ + for (int i = 0; i < isp->num_ipc_chans; i++) { + struct isp_channel *chan = isp->ipc_chans[i]; + if (chan->type != ISP_IPC_CHAN_TYPE_COMMAND) + continue; + for (int j = 0; j < chan->num; j++) { + struct isp_message msg; + dma_addr_t msg_iova = chan->iova + (j * sizeof(msg)); + + memset(&msg, 0, sizeof(msg)); + msg.arg0 = ISP_IPC_FLAG_ACK; + isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); + } + } + + /* Wait for ISP_CORE_GPIO_3 to 0x8042006 -> 0x0 */ + isp_core_write32(isp, ISP_CORE_GPIO_3, 0x8042006); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_3); + if (val == 0x0) { + isp_dbg(isp, + "got third magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, + "never received third magic number from firmware\n"); + isp_free_channel_info(isp); + return -ENODEV; + } + + isp_dbg(isp, "firmware booted!\n"); + + return 0; +} + +static int isp_stop_command_processor(struct apple_isp *isp) +{ + int retries; + + /* Wait for ISP_CORE_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ + isp_core_write32(isp, ISP_CORE_GPIO_0, 0xf7fbdff9); + + /* Their CISP_CMD_STOP implementation is buggy */ + isp_cmd_suspend(isp); + + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { + u32 val = isp_core_read32(isp, ISP_CORE_GPIO_0); + if (val == 0x8042006) { + isp_dbg(isp, "got magic number (0x%x) from firmware\n", + val); + break; + } + mdelay(ISP_FIRMWARE_MDELAY); + } + if (retries >= ISP_FIRMWARE_MAX_TRIES) { + isp_err(isp, "never received magic number from firmware\n"); + return -ENODEV; + } + + return 0; +} + +static int isp_start_command_processor(struct apple_isp *isp) +{ + int err; + + err = isp_cmd_print_enable(isp, 1); + if (err) + return err; + + err = isp_cmd_set_isp_pmu_base(isp, isp->hw->pmu_base); + if (err) + return err; + + err = isp_cmd_set_dsid_clr_req_base2( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, + isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, + isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, + isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); + if (err) + return err; + + err = isp_cmd_pmp_ctrl_set( + isp, isp->hw->clock_scratch, isp->hw->clock_base, + isp->hw->clock_bit, isp->hw->clock_size, + isp->hw->bandwidth_scratch, isp->hw->bandwidth_base, + isp->hw->bandwidth_bit, isp->hw->bandwidth_size); + if (err) + return err; + + err = isp_cmd_start(isp, 0); + if (err) + return err; + + /* Now we can access CISP_CMD_CH_* commands */ + + return 0; +} + +static void isp_collect_gc_surface(struct apple_isp *isp) +{ + struct isp_surf *tmp, *surf; + list_for_each_entry_safe_reverse(surf, tmp, &isp->gc, head) { + isp_dbg(isp, "freeing iova: 0x%llx size: 0x%llx virt: %pS\n", + surf->iova, surf->size, (void *)surf->virt); + isp_free_surface(isp, surf); + } +} + +static int isp_firmware_boot(struct apple_isp *isp) +{ + int err; + + err = isp_firmware_boot_stage1(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 1: %d\n", err); + goto garbage_collect; + } + + err = isp_firmware_boot_stage2(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 2: %d\n", err); + goto shutdown_stage1; + } + + err = isp_firmware_boot_stage3(isp); + if (err < 0) { + isp_err(isp, "failed firmware boot stage 3: %d\n", err); + goto shutdown_stage2; + } + + err = isp_enable_irq(isp); + if (err < 0) { + isp_err(isp, "failed to enable interrupts: %d\n", err); + goto shutdown_stage3; + } + + err = isp_start_command_processor(isp); + if (err < 0) { + isp_err(isp, "failed to start command processor: %d\n", err); + goto disable_irqs; + } + + flush_workqueue(isp->wq); + + return 0; + +disable_irqs: + isp_disable_irq(isp); +shutdown_stage3: + isp_firmware_shutdown_stage3(isp); +shutdown_stage2: + isp_firmware_shutdown_stage2(isp); +shutdown_stage1: + isp_firmware_shutdown_stage1(isp); +garbage_collect: + isp_collect_gc_surface(isp); + return err; +} + +static void isp_firmware_shutdown(struct apple_isp *isp) +{ + flush_workqueue(isp->wq); + isp_stop_command_processor(isp); + isp_disable_irq(isp); + isp_firmware_shutdown_stage3(isp); + isp_firmware_shutdown_stage2(isp); + isp_firmware_shutdown_stage1(isp); + isp_collect_gc_surface(isp); +} + +int apple_isp_firmware_boot(struct apple_isp *isp) +{ + int err; + + /* Needs to be power cycled for IOMMU to behave correctly */ + err = pm_runtime_resume_and_get(isp->dev); + if (err < 0) { + dev_err(isp->dev, "failed to enable power: %d\n", err); + return err; + } + + err = isp_firmware_boot(isp); + if (err) { + dev_err(isp->dev, "failed to boot firmware: %d\n", err); + pm_runtime_put_sync(isp->dev); + return err; + } + + return 0; +} + +void apple_isp_firmware_shutdown(struct apple_isp *isp) +{ + isp_firmware_shutdown(isp); + pm_runtime_put_sync(isp->dev); +} diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h new file mode 100644 index 00000000000000..ad9f4fdf641aaa --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_FW_H__ +#define __ISP_FW_H__ + +#include "isp-drv.h" + +int apple_isp_firmware_boot(struct apple_isp *isp); +void apple_isp_firmware_shutdown(struct apple_isp *isp); + +#endif /* __ISP_FW_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c new file mode 100644 index 00000000000000..ede4fe8e226913 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -0,0 +1,274 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include + +#include "isp-iommu.h" + +void apple_isp_iommu_sync_ttbr(struct apple_isp *isp) +{ + writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart1 + isp->hw->ttbr); + writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart2 + isp->hw->ttbr); +} + +void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp) +{ + iommu_flush_iotlb_all(isp->domain); + writel(0x1, isp->dart1 + isp->hw->stream_select); + writel(isp->hw->stream_command_invalidate, + isp->dart1 + isp->hw->stream_command); + writel(0x1, isp->dart2 + isp->hw->stream_select); + writel(isp->hw->stream_command_invalidate, + isp->dart2 + isp->hw->stream_command); +} + +static void isp_surf_free_pages(struct isp_surf *surf) +{ + for (u32 i = 0; i < surf->num_pages && surf->pages[i] != NULL; i++) { + __free_page(surf->pages[i]); + } + kvfree(surf->pages); +} + +static int isp_surf_alloc_pages(struct isp_surf *surf) +{ + surf->pages = kvmalloc_array(surf->num_pages, sizeof(*surf->pages), + GFP_KERNEL); + if (!surf->pages) + return -ENOMEM; + + for (u32 i = 0; i < surf->num_pages; i++) { + surf->pages[i] = alloc_page(GFP_KERNEL); + if (surf->pages[i] == NULL) + goto free_pages; + } + + return 0; + +free_pages: + isp_surf_free_pages(surf); + return -ENOMEM; +} + +int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf) +{ + surf->virt = vmap(surf->pages, surf->num_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (surf->virt == NULL) { + dev_err(isp->dev, "failed to vmap size 0x%llx\n", surf->size); + return -EINVAL; + } + + return 0; +} + +static void isp_surf_vunmap(struct apple_isp *isp, struct isp_surf *surf) +{ + if (surf->virt) + vunmap(surf->virt); + surf->virt = NULL; +} + +static void isp_surf_unreserve_iova(struct apple_isp *isp, + struct isp_surf *surf) +{ + if (surf->mm) { + mutex_lock(&isp->iovad_lock); + drm_mm_remove_node(surf->mm); + mutex_unlock(&isp->iovad_lock); + kfree(surf->mm); + } + surf->mm = NULL; +} + +static int isp_surf_reserve_iova(struct apple_isp *isp, struct isp_surf *surf) +{ + int err; + + surf->mm = kzalloc(sizeof(*surf->mm), GFP_KERNEL); + if (!surf->mm) + return -ENOMEM; + + mutex_lock(&isp->iovad_lock); + err = drm_mm_insert_node_generic(&isp->iovad, surf->mm, + ALIGN(surf->size, 1UL << isp->shift), + 1UL << isp->shift, 0, 0); + mutex_unlock(&isp->iovad_lock); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + goto mm_free; + } + + surf->iova = surf->mm->start; + + return 0; +mm_free: + kfree(surf->mm); + surf->mm = NULL; + return err; +} + +static void isp_surf_iommu_unmap(struct apple_isp *isp, struct isp_surf *surf) +{ + iommu_unmap(isp->domain, surf->iova, surf->size); + apple_isp_iommu_invalidate_tlb(isp); + sg_free_table(&surf->sgt); +} + +static int isp_surf_iommu_map(struct apple_isp *isp, struct isp_surf *surf) +{ + unsigned long size; + int err; + + err = sg_alloc_table_from_pages(&surf->sgt, surf->pages, + surf->num_pages, 0, surf->size, + GFP_KERNEL); + if (err < 0) { + dev_err(isp->dev, "failed to alloc sgt from pages\n"); + return err; + } + + size = iommu_map_sgtable(isp->domain, surf->iova, &surf->sgt, + IOMMU_READ | IOMMU_WRITE); + if (size < surf->size) { + dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", + surf->iova); + sg_free_table(&surf->sgt); + return -ENXIO; + } + + return 0; +} + +static void __isp_surf_init(struct apple_isp *isp, struct isp_surf *surf, + u64 size, bool gc) +{ + surf->mm = NULL; + surf->virt = NULL; + surf->size = ALIGN(size, 1UL << isp->shift); + surf->num_pages = surf->size >> isp->shift; + surf->gc = gc; +} + +struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc) +{ + int err; + + struct isp_surf *surf = kzalloc(sizeof(struct isp_surf), GFP_KERNEL); + if (!surf) + return NULL; + + __isp_surf_init(isp, surf, size, gc); + + err = isp_surf_alloc_pages(surf); + if (err < 0) { + dev_err(isp->dev, "failed to allocate %d pages\n", + surf->num_pages); + goto free_surf; + } + + err = isp_surf_reserve_iova(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + goto free_pages; + } + + err = isp_surf_iommu_map(isp, surf); + if (err < 0) { + dev_err(isp->dev, + "failed to iommu_map size 0x%llx to iova 0x%llx\n", + surf->size, surf->iova); + goto unreserve_iova; + } + + refcount_set(&surf->refcount, 1); + if (surf->gc) + list_add_tail(&surf->head, &isp->gc); + + return surf; + +unreserve_iova: + isp_surf_unreserve_iova(isp, surf); +free_pages: + isp_surf_free_pages(surf); +free_surf: + kfree(surf); + return NULL; +} + +struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size) +{ + int err; + + struct isp_surf *surf = __isp_alloc_surface(isp, size, false); + if (!surf) + return NULL; + + err = isp_surf_vmap(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to vmap iova 0x%llx - 0x%llx\n", + surf->iova, surf->iova + surf->size); + isp_free_surface(isp, surf); + return NULL; + } + + return surf; +} + +void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf) +{ + if (refcount_dec_and_test(&surf->refcount)) { + isp_surf_vunmap(isp, surf); + isp_surf_iommu_unmap(isp, surf); + isp_surf_unreserve_iova(isp, surf); + isp_surf_free_pages(surf); + if (surf->gc) + list_del(&surf->head); + kfree(surf); + } +} + +void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova) +{ + phys_addr_t phys = iommu_iova_to_phys(isp->domain, iova); + return phys_to_virt(phys); +} + +int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, + struct sg_table *sgt, u64 size) +{ + int err; + ssize_t mapped; + + // TODO userptr sends unaligned sizes + surf->mm = NULL; + surf->size = size; + + err = isp_surf_reserve_iova(isp, surf); + if (err < 0) { + dev_err(isp->dev, "failed to reserve 0x%llx of iova space\n", + surf->size); + return err; + } + + mapped = iommu_map_sgtable(isp->domain, surf->iova, sgt, + IOMMU_READ | IOMMU_WRITE); + if (mapped < surf->size) { + dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", + surf->iova); + isp_surf_unreserve_iova(isp, surf); + return -ENXIO; + } + surf->size = mapped; + + return 0; +} + +void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf) +{ + iommu_unmap(isp->domain, surf->iova, surf->size); + apple_isp_iommu_invalidate_tlb(isp); + isp_surf_unreserve_iova(isp, surf); +} diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h new file mode 100644 index 00000000000000..f9972bd9ff93e7 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_IOMMU_H__ +#define __ISP_IOMMU_H__ + +#include "isp-drv.h" + +void apple_isp_iommu_sync_ttbr(struct apple_isp *isp); +void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp); + +struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); +#define isp_alloc_surface(isp, size) (__isp_alloc_surface(isp, size, false)) +#define isp_alloc_surface_gc(isp, size) (__isp_alloc_surface(isp, size, true)) +struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size); +int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf); +void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf); +void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova); + +static inline void isp_ioread(struct apple_isp *isp, dma_addr_t iova, + void *data, u64 size) +{ + void *virt = isp_iotranslate(isp, iova); + memcpy(data, virt, size); +} + +static inline void isp_iowrite(struct apple_isp *isp, dma_addr_t iova, + void *data, u64 size) +{ + void *virt = isp_iotranslate(isp, iova); + memcpy(virt, data, size); +} + +int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, + struct sg_table *sgt, u64 size); +void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf); + +#endif /* __ISP_IOMMU_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c new file mode 100644 index 00000000000000..ef3498c4fcd191 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -0,0 +1,329 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-regs.h" + +#define ISP_IPC_FLAG_TERMINAL_ACK 0x3 +#define ISP_IPC_BUFEXC_STAT_META_OFFSET 0x10 + +struct isp_sm_deferred_work { + struct work_struct work; + struct apple_isp *isp; + struct isp_surf *surf; +}; + +struct isp_bufexc_stat { + u64 unk_0; // 2 + u64 unk_8; // 2 + + u64 meta_iova; + u64 pad_20[3]; + u64 meta_size; // 0x4640 + u64 unk_38; + + u32 unk_40; // 1 + u32 unk_44; + u64 unk_48; + + u64 iova0; + u64 iova1; + u64 iova2; + u64 iova3; + u32 pad_70[4]; + + u32 unk_80; // 2 + u32 unk_84; // 1 + u32 unk_88; // 0x10 || 0x13 + u32 unk_8c; + u32 pad_90[96]; + + u32 unk_210; // 0x28 + u32 unk_214; + u32 index; + u16 bes_width; // 1296, 0x510 + u16 bes_height; // 736, 0x2e0 + + u32 unk_220; // 0x0 || 0x1 + u32 pad_224[3]; + u32 unk_230; // 0xf7ed38 + u32 unk_234; // 3 + u32 pad_238[2]; + u32 pad_240[16]; +} __packed; +static_assert(sizeof(struct isp_bufexc_stat) == ISP_IPC_BUFEXC_STAT_SIZE); + +static inline dma_addr_t chan_msg_iova(struct isp_channel *chan, u32 index) +{ + return chan->iova + (index * ISP_IPC_MESSAGE_SIZE); +} + +static inline void chan_read_msg_index(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg, u32 index) +{ + isp_ioread(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); +} + +static inline void chan_read_msg(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg) +{ + chan_read_msg_index(isp, chan, msg, chan->cursor); +} + +static inline void chan_write_msg_index(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg, u32 index) +{ + isp_iowrite(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); +} + +static inline void chan_write_msg(struct apple_isp *isp, + struct isp_channel *chan, + struct isp_message *msg) +{ + chan_write_msg_index(isp, chan, msg, chan->cursor); +} + +static inline void chan_update_cursor(struct isp_channel *chan) +{ + if (chan->cursor >= (chan->num - 1)) { + chan->cursor = 0; + } else { + chan->cursor += 1; + } +} + +static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) +{ + int err; + + lockdep_assert_held(&chan->lock); + + err = chan->ops->handle(isp, chan); + if (err < 0) { + dev_err(isp->dev, "%s: handler failed: %d)\n", chan->name, err); + return err; + } + + chan_write_msg(isp, chan, &chan->rsp); + + isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + + chan_update_cursor(chan); + + return 0; +} + +static inline bool chan_rx_done(struct apple_isp *isp, struct isp_channel *chan) +{ + if (((chan->req.arg0 & 0xf) == ISP_IPC_FLAG_ACK) || + ((chan->req.arg0 & 0xf) == ISP_IPC_FLAG_TERMINAL_ACK)) { + return true; + } + return false; +} + +int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + int err = 0; + + spin_lock(&chan->lock); + while (1) { + chan_read_msg(isp, chan, &chan->req); + if (chan_rx_done(isp, chan)) { + err = 0; + break; + } + err = chan_handle_once(isp, chan); + if (err < 0) { + break; + } + } + spin_unlock(&chan->lock); + + return err; +} + +static inline bool chan_tx_done(struct apple_isp *isp, struct isp_channel *chan) +{ + chan_read_msg(isp, chan, &chan->rsp); + if ((chan->rsp.arg0) == (chan->req.arg0 | ISP_IPC_FLAG_ACK)) { + chan_update_cursor(chan); + return true; + } + return false; +} + +int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, + unsigned long timeout) +{ + long t; + + chan_write_msg(isp, chan, &chan->req); + wmb(); + + isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + + t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), + timeout); + if (t == 0) { + dev_err(isp->dev, + "%s: timed out on request [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, chan->req.arg0, chan->req.arg1, + chan->req.arg2); + return -ETIME; + } + + isp_dbg(isp, "%s: request success (%ld)\n", chan->name, t); + + return 0; +} + +int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *rsp = &chan->rsp; + +#ifdef APPLE_ISP_DEBUG + struct isp_message *req = &chan->req; + char buf[512]; + dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; + u32 size = req->arg1; + if (iova && size && test_bit(ISP_STATE_LOGGING, &isp->state)) { + size = min_t(u32, size, 512); + isp_ioread(isp, iova, buf, size); + isp_dbg(isp, "ISPASC: %.*s", size, buf); + } +#endif + + rsp->arg0 = ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; + + return 0; +} + +/* The kernel accesses exactly two dynamically allocated shared surfaces: + * 1) LOG: Surface for terminal logs. Optional, only enabled in debug builds. + * 2) STAT: Surface for BUFT2H rendered frame stat buffer. We isp_ioread() in + * the BUFT2H ISR below. Since the BUFT2H IRQ is triggered by the BUF_H2T + * doorbell, the STAT vmap must complete before the first buffer submission + * under VIDIOC_STREAMON(). The CISP_CMD_PRINT_ENABLE completion depends on the + * STAT buffer SHAREDMALLOC ISR, which is part of the firmware initialization + * sequence. We also call flush_workqueue(), so a fault should not occur. + */ +static void sm_malloc_deferred_worker(struct work_struct *work) +{ + struct isp_sm_deferred_work *dwork = + container_of(work, struct isp_sm_deferred_work, work); + struct apple_isp *isp = dwork->isp; + struct isp_surf *surf = dwork->surf; + int err; + + err = isp_surf_vmap(isp, surf); /* Can't vmap in interrupt ctx */ + if (err < 0) { + isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", + surf->iova, surf->size); + goto out; + } + +#ifdef APPLE_ISP_DEBUG + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. + */ + if (!test_bit(ISP_STATE_LOGGING, &isp->state)) + set_bit(ISP_STATE_LOGGING, &isp->state); +#endif + +out: + kfree(dwork); +} + +int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + + if (req->arg0 == 0x0) { + struct isp_sm_deferred_work *dwork; + struct isp_surf *surf; + + dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); + if (!dwork) + return -ENOMEM; + dwork->isp = isp; + + surf = isp_alloc_surface_gc(isp, req->arg1); + if (!surf) { + isp_err(isp, "failed to alloc requested size 0x%llx\n", + req->arg1); + kfree(dwork); + return -ENOMEM; + } + dwork->surf = surf; + + rsp->arg0 = surf->iova | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ + + INIT_WORK(&dwork->work, sm_malloc_deferred_worker); + if (!queue_work(isp->wq, &dwork->work)) { + isp_err(isp, "failed to queue deferred work\n"); + isp_free_surface(isp, surf); + kfree(dwork); + return -ENOMEM; + } + /* To the gc it goes... */ + + } else { + /* This should be the shared surface free request, but + * 1) The fw doesn't request to free all of what it requested + * 2) The fw continues to access the surface after + * So we link it to the gc, which runs after fw shutdown + */ +#ifdef APPLE_ISP_DEBUG + if (test_bit(ISP_STATE_LOGGING, &isp->state)) + clear_bit(ISP_STATE_LOGGING, &isp->state); +#endif + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = 0x0; + } + + return 0; +} + +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + struct isp_buffer *tmp, *buf; + int err = 0; + + /* No need to read the whole struct */ + u64 meta_iova; + isp_ioread(isp, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, &meta_iova, + sizeof(meta_iova)); + + spin_lock(&isp->buf_lock); + list_for_each_entry_safe_reverse(buf, tmp, &isp->buffers, link) { + if (buf->meta->iova == meta_iova) { + enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); + buf->vb.sequence = isp->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + if (req->arg2 == ISP_IPC_BUFEXC_FLAG_RENDER) + state = VB2_BUF_STATE_DONE; + vb2_buffer_done(&buf->vb.vb2_buf, state); + list_del(&buf->link); + break; + } + } + spin_unlock(&isp->buf_lock); + + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; + + return err; +} diff --git a/drivers/media/platform/apple/isp/isp-ipc.h b/drivers/media/platform/apple/isp/isp-ipc.h new file mode 100644 index 00000000000000..32d1e1bf321006 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-ipc.h @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_IPC_H__ +#define __ISP_IPC_H__ + +#include "isp-drv.h" + +#define ISP_IPC_CHAN_TYPE_COMMAND 0 +#define ISP_IPC_CHAN_TYPE_REPLY 1 +#define ISP_IPC_CHAN_TYPE_REPORT 2 + +#define ISP_IPC_BUFEXC_STAT_SIZE 0x280 +#define ISP_IPC_BUFEXC_FLAG_RENDER 0x10000000 +#define ISP_IPC_BUFEXC_FLAG_COMMAND 0x30000000 +#define ISP_IPC_BUFEXC_FLAG_ACK 0x80000000 + +int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, + unsigned long timeout); + +int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan); +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); + +#endif /* __ISP_IPC_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h new file mode 100644 index 00000000000000..b9bd505844d9de --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_REGS_H__ +#define __ISP_REGS_H__ + +#include "isp-drv.h" + +#define ISP_ASC_PMGR_0 0x738 +#define ISP_ASC_PMGR_1 0x798 +#define ISP_ASC_PMGR_2 0x7f8 +#define ISP_ASC_PMGR_3 0x858 + +#define ISP_ASC_RVBAR 0x1050000 +#define ISP_ASC_EDPRCR 0x1010310 +#define ISP_ASC_CONTROL 0x1400044 +#define ISP_ASC_STATUS 0x1400048 + +#define ISP_ASC_IRQ_MASK_0 0x1400a00 +#define ISP_ASC_IRQ_MASK_1 0x1400a04 +#define ISP_ASC_IRQ_MASK_2 0x1400a08 +#define ISP_ASC_IRQ_MASK_3 0x1400a0c +#define ISP_ASC_IRQ_MASK_4 0x1400a10 +#define ISP_ASC_IRQ_MASK_5 0x1400a14 + +#define ISP_CORE_IRQ_INTERRUPT 0x2104000 +#define ISP_CORE_IRQ_ENABLE 0x2104004 +#define ISP_CORE_IRQ_DOORBELL 0x21043f0 +#define ISP_CORE_IRQ_ACK 0x21043fc + +#define ISP_CORE_GPIO_0 0x2104170 +#define ISP_CORE_GPIO_1 0x2104174 +#define ISP_CORE_GPIO_2 0x2104178 +#define ISP_CORE_GPIO_3 0x210417c +#define ISP_CORE_GPIO_4 0x2104180 +#define ISP_CORE_GPIO_5 0x2104184 +#define ISP_CORE_GPIO_6 0x2104188 +#define ISP_CORE_GPIO_7 0x210418c + +#define ISP_CORE_CLOCK_EN 0x2104190 + +#define ISP_CORE_DPE_CTRL_0 0x2504000 +#define ISP_CORE_DPE_CTRL_1 0x2508000 + +static inline u32 isp_core_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->core + reg - 0x2104000); // TODO this sucks +} + +static inline void isp_core_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->core + reg - 0x2104000); +} + +static inline void isp_core_mask32(struct apple_isp *isp, u32 reg, u32 clear, + u32 set) +{ + isp_core_write32(isp, reg, isp_core_read32(isp, reg) & ~clear); + isp_core_write32(isp, reg, isp_core_read32(isp, reg) | set); +} + +#endif /* __ISP_REGS_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c new file mode 100644 index 00000000000000..abdda01bfa2cec --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -0,0 +1,602 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#include +#include +#include +#include +#include + +#include "isp-cam.h" +#include "isp-cmd.h" +#include "isp-iommu.h" +#include "isp-ipc.h" +#include "isp-v4l2.h" + +#define ISP_MIN_FRAMES 2 +#define ISP_MAX_PLANES 4 +#define ISP_MAX_PIX_FORMATS 2 +#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) + +struct isp_h2t_buffer { + u64 iovas[ISP_MAX_PLANES]; + u32 flags[ISP_MAX_PLANES]; + u32 num_planes; + u32 pool_type; + u32 tag; + u32 pad; +} __packed; +static_assert(sizeof(struct isp_h2t_buffer) == 0x40); + +struct isp_h2t_args { + u64 enable; + u64 num_buffers; + struct isp_h2t_buffer meta; + struct isp_h2t_buffer render; +} __packed; + +static int isp_submit_buffers(struct apple_isp *isp) +{ + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_channel *chan = isp->chan_bh; + struct isp_message *req = &chan->req; + struct isp_buffer *buf; + unsigned long flags; + size_t offset; + int err; + + struct isp_h2t_args *args = + kzalloc(sizeof(struct isp_h2t_args), GFP_KERNEL); + if (!args) + return -ENOMEM; + + spin_lock_irqsave(&isp->buf_lock, flags); + buf = list_first_entry_or_null(&isp->buffers, struct isp_buffer, link); + if (!buf) { + spin_unlock_irqrestore(&isp->buf_lock, flags); + kfree(args); + return -EPROTO; + } + + args->meta.num_planes = 1; + args->meta.pool_type = CISP_POOL_TYPE_META; + args->meta.iovas[0] = buf->meta->iova; + args->meta.flags[0] = 0x40000000; + + args->render.num_planes = fmt->num_planes; + args->render.pool_type = CISP_POOL_TYPE_RENDERED; + offset = 0; + for (int j = 0; j < fmt->num_planes; j++) { + args->render.iovas[j] = buf->surfs[0].iova + offset; + args->render.flags[j] = 0x40000000; + offset += fmt->plane_size[j]; + } + spin_unlock_irqrestore(&isp->buf_lock, flags); + + args->enable = 0x1; + args->num_buffers = 2; + + req->arg0 = isp->cmd_iova; + req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + isp_iowrite(isp, req->arg0, args, sizeof(*args)); + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + } + + kfree(args); + + return err; +} + +/* + * Videobuf2 section + */ +static int isp_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct apple_isp *isp = vb2_get_drv_priv(vq); + struct isp_format *fmt = isp_get_current_format(isp); + + if (*num_planes) { + if (sizes[0] < fmt->total_size) + return -EINVAL; + + return 0; + } + + *num_planes = 1; + sizes[0] = fmt->total_size; + + return 0; +} + +static void __isp_vb2_buf_cleanup(struct vb2_buffer *vb, unsigned int i) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + + while (i--) + apple_isp_iommu_unmap_sgt(isp, &buf->surfs[i]); + isp_free_surface(isp, buf->meta); +} + +static void isp_vb2_buf_cleanup(struct vb2_buffer *vb) +{ + __isp_vb2_buf_cleanup(vb, vb->num_planes); +} + +static int isp_vb2_buf_init(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + unsigned int i; + int err; + + buf->meta = isp_alloc_surface(isp, ISP_META_SIZE); + if (!buf->meta) + return -ENOMEM; + + for (i = 0; i < vb->num_planes; i++) { + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i); + err = apple_isp_iommu_map_sgt(isp, &buf->surfs[i], sgt, + vb2_plane_size(vb, i)); + if (err) + goto cleanup; + } + + return 0; + +cleanup: + __isp_vb2_buf_cleanup(vb, i); + return err; +} + +static int isp_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_format *fmt = isp_get_current_format(isp); + + if (vb2_plane_size(vb, 0) < fmt->total_size) + return -EINVAL; + + vb2_set_plane_payload(vb, 0, fmt->total_size); + + return 0; +} + +static void isp_vb2_release_buffers(struct apple_isp *isp, + enum vb2_buffer_state state) +{ + struct isp_buffer *buf; + unsigned long flags; + + spin_lock_irqsave(&isp->buf_lock, flags); + list_for_each_entry(buf, &isp->buffers, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&isp->buffers); + spin_unlock_irqrestore(&isp->buf_lock, flags); +} + +static void isp_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct apple_isp *isp = vb2_get_drv_priv(vb->vb2_queue); + struct isp_buffer *buf = + container_of(vb, struct isp_buffer, vb.vb2_buf); + unsigned long flags; + bool empty; + + spin_lock_irqsave(&isp->buf_lock, flags); + empty = list_empty(&isp->buffers); + list_add_tail(&buf->link, &isp->buffers); + spin_unlock_irqrestore(&isp->buf_lock, flags); + + if (test_bit(ISP_STATE_STREAMING, &isp->state) && !empty) + isp_submit_buffers(isp); +} + +static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + int err; + + isp->sequence = 0; + + err = apple_isp_start_camera(isp); + if (err) { + dev_err(isp->dev, "failed to start camera: %d\n", err); + goto release_buffers; + } + + err = isp_submit_buffers(isp); + if (err) { + dev_err(isp->dev, "failed to send initial batch: %d\n", err); + goto stop_camera; + } + + err = apple_isp_start_capture(isp); + if (err) { + dev_err(isp->dev, "failed to start capture: %d\n", err); + goto stop_camera; + } + + set_bit(ISP_STATE_STREAMING, &isp->state); + + return 0; + +stop_camera: + apple_isp_stop_camera(isp); +release_buffers: + isp_vb2_release_buffers(isp, VB2_BUF_STATE_QUEUED); + return err; +} + +static void isp_vb2_stop_streaming(struct vb2_queue *q) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + clear_bit(ISP_STATE_STREAMING, &isp->state); + apple_isp_stop_capture(isp); + apple_isp_stop_camera(isp); + isp_vb2_release_buffers(isp, VB2_BUF_STATE_ERROR); +} + +static const struct vb2_ops isp_vb2_ops = { + .queue_setup = isp_vb2_queue_setup, + .buf_init = isp_vb2_buf_init, + .buf_cleanup = isp_vb2_buf_cleanup, + .buf_prepare = isp_vb2_buf_prepare, + .buf_queue = isp_vb2_buf_queue, + .start_streaming = isp_vb2_start_streaming, + .stop_streaming = isp_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* + * V4L2 ioctl section + */ +static int isp_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->card, APPLE_ISP_DEVICE_NAME, sizeof(cap->card)); + strscpy(cap->driver, APPLE_ISP_DEVICE_NAME, sizeof(cap->driver)); + + return 0; +} + +static int isp_vidioc_enum_format(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index >= ISP_MAX_PIX_FORMATS) + return -EINVAL; + + if (!f->index) + f->pixelformat = V4L2_PIX_FMT_NV12; + else + f->pixelformat = V4L2_PIX_FMT_NV12M; + + return 0; +} + +static int isp_vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *f) +{ + struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + + if (f->index >= ISP_MAX_PIX_FORMATS) + return -EINVAL; + + if ((!f->index && f->pixel_format != V4L2_PIX_FMT_NV12) || + (f->index && f->pixel_format != V4L2_PIX_FMT_NV12M)) + return -EINVAL; + + f->discrete.width = fmt->width; + f->discrete.height = fmt->height; + f->type = V4L2_FRMSIZE_TYPE_DISCRETE; + + return 0; +} + +static inline void isp_set_sp_pix_format(struct apple_isp *isp, + struct v4l2_format *f) +{ + struct isp_format *fmt = isp_get_current_format(isp); + + f->fmt.pix.width = fmt->width; + f->fmt.pix.height = fmt->height; + f->fmt.pix.sizeimage = fmt->total_size; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12; + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix.ycbcr_enc = V4L2_YCBCR_ENC_709; + f->fmt.pix.xfer_func = V4L2_XFER_FUNC_709; +} + +static inline void isp_set_mp_pix_format(struct apple_isp *isp, + struct v4l2_format *f) +{ + struct isp_format *fmt = isp_get_current_format(isp); + + f->fmt.pix_mp.width = fmt->width; + f->fmt.pix_mp.height = fmt->height; + f->fmt.pix_mp.num_planes = fmt->num_planes; + for (int i = 0; i < fmt->num_planes; i++) + f->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->plane_size[i]; + + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_709; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_709; +} + +static int isp_vidioc_get_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); + + return 0; +} + +static int isp_vidioc_set_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); // no + + return 0; +} + +static int isp_vidioc_try_format(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (isp->multiplanar) + return -ENOTTY; + + isp_set_sp_pix_format(isp, f); // still no + + return 0; +} + +static int isp_vidioc_get_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); + + return 0; +} + +static int isp_vidioc_set_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); // no + + return 0; +} + +static int isp_vidioc_try_format_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct apple_isp *isp = video_drvdata(file); + + if (!isp->multiplanar) + return -ENOTTY; + + isp_set_mp_pix_format(isp, f); // still no + + return 0; +} + +static int isp_vidioc_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + if (inp->index) + return -EINVAL; + + strscpy(inp->name, APPLE_ISP_DEVICE_NAME, sizeof(inp->name)); + inp->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +static int isp_vidioc_get_input(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int isp_vidioc_set_input(struct file *file, void *fh, unsigned int i) +{ + if (i) + return -EINVAL; + + return 0; +} + +static int isp_vidioc_get_param(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct apple_isp *isp = video_drvdata(file); + + if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = ISP_MIN_FRAMES; + a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; + a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; + + return 0; +} + +static int isp_vidioc_set_param(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct apple_isp *isp = video_drvdata(file); + + if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + /* Not supporting frame rate sets. No use. Plus floats. */ + a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; + a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; + + return 0; +} + +static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { + .vidioc_querycap = isp_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, + .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, + .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, + .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, + .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, + .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, + .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, + + .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_input = isp_vidioc_enum_input, + .vidioc_g_input = isp_vidioc_get_input, + .vidioc_s_input = isp_vidioc_set_input, + .vidioc_g_parm = isp_vidioc_get_param, + .vidioc_s_parm = isp_vidioc_set_param, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static const struct v4l2_file_operations isp_v4l2_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct media_device_ops isp_media_device_ops = { + .link_notify = v4l2_pipeline_link_notify, +}; + +int apple_isp_setup_video(struct apple_isp *isp) +{ + struct video_device *vdev = &isp->vdev; + struct vb2_queue *vbq = &isp->vbq; + int err; + + media_device_init(&isp->mdev); + isp->v4l2_dev.mdev = &isp->mdev; + isp->mdev.ops = &isp_media_device_ops; + isp->mdev.dev = isp->dev; + strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, sizeof(isp->mdev.model)); + + err = media_device_register(&isp->mdev); + if (err) { + dev_err(isp->dev, "failed to register media device: %d\n", err); + goto media_cleanup; + } + + isp->multiplanar = 0; + + err = v4l2_device_register(isp->dev, &isp->v4l2_dev); + if (err) { + dev_err(isp->dev, "failed to register v4l2 device: %d\n", err); + goto media_unregister; + } + + vbq->drv_priv = isp; + vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + vbq->io_modes = VB2_MMAP; + vbq->dev = isp->dev; + vbq->ops = &isp_vb2_ops; + vbq->mem_ops = &vb2_dma_sg_memops; + vbq->buf_struct_size = sizeof(struct isp_buffer); + vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vbq->min_buffers_needed = ISP_MIN_FRAMES; + vbq->lock = &isp->video_lock; + + err = vb2_queue_init(vbq); + if (err) { + dev_err(isp->dev, "failed to init vb2 queue: %d\n", err); + goto v4l2_unregister; + } + + vdev->queue = vbq; + vdev->fops = &isp_v4l2_fops; + vdev->ioctl_ops = &isp_v4l2_ioctl_ops; + vdev->device_caps = V4L2_BUF_TYPE_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->v4l2_dev = &isp->v4l2_dev; + vdev->vfl_type = VFL_TYPE_VIDEO; + vdev->vfl_dir = VFL_DIR_RX; + vdev->release = video_device_release_empty; + vdev->lock = &isp->video_lock; + strscpy(vdev->name, APPLE_ISP_DEVICE_NAME, sizeof(vdev->name)); + video_set_drvdata(vdev, isp); + + err = video_register_device(vdev, VFL_TYPE_VIDEO, 0); + if (err) { + dev_err(isp->dev, "failed to register video device: %d\n", err); + goto v4l2_unregister; + } + + return 0; + +v4l2_unregister: + v4l2_device_unregister(&isp->v4l2_dev); +media_unregister: + media_device_unregister(&isp->mdev); +media_cleanup: + media_device_cleanup(&isp->mdev); + return err; +} + +void apple_isp_remove_video(struct apple_isp *isp) +{ + vb2_video_unregister_device(&isp->vdev); + v4l2_device_unregister(&isp->v4l2_dev); + media_device_unregister(&isp->mdev); + media_device_cleanup(&isp->mdev); +} diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h new file mode 100644 index 00000000000000..df9b961d77bc17 --- /dev/null +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright 2023 Eileen Yoon */ + +#ifndef __ISP_V4L2_H__ +#define __ISP_V4L2_H__ + +#include "isp-drv.h" + +int apple_isp_setup_video(struct apple_isp *isp); +void apple_isp_remove_video(struct apple_isp *isp); + +#endif /* __ISP_V4L2_H__ */ From 8374ff5486bec6b7bf6cfa0aef3ace1ceb3f830d Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sat, 2 Sep 2023 00:47:39 +0900 Subject: [PATCH 02/60] media: apple: isp: IMX558 initial support Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-cam.c | 5 +- drivers/media/platform/apple/isp/isp-drv.c | 54 ++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 6d08248ef44776..bb90337cb7c19f 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -78,12 +78,13 @@ static const struct isp_setfile isp_setfiles[] = { [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, }; -// clang-format on // one day we will do this intelligently static const struct isp_preset isp_presets[] = { - [ISP_IMX248_1820_01] = { 0, 1280, 720, 8, 8, 1280, 720, 1296, 736 }, + [ISP_IMX248_1820_01] = {0, 1280, 720, 8, 8, 1280, 720, 1296, 736}, // J293AP + [ISP_IMX558_1921_01] = {1, 1920, 1080, 0, 0, 1920, 1080, 1920, 1080}, // J316sAP, J415AP }; +// clang-format on static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) { diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index e1f7842ed09b36..3ec7c66b48add5 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -292,6 +292,60 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; +static const struct apple_isp_hw apple_isp_hw_t6000 = { + .pmu_base = 0x28e584000, + + .dsid_clr_base0 = 0x200014000, + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x28e3d0868, + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x28e3d0980, + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, + + .stream_command = DART_T8020_STREAM_COMMAND, + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + +static const struct apple_isp_hw apple_isp_hw_t8110 = { + .pmu_base = 0x23b704000, + + .dsid_clr_base0 = 0x200014000, // TODO + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x23b3d0560, + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x23b3d05d0, + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, + + .stream_command = DART_T8020_STREAM_COMMAND, // TODO + .stream_select = DART_T8020_STREAM_SELECT, + .ttbr = DART_T8020_TTBR, + .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, +}; + static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, {}, From 4d01f9c289f304935bd6ad9784cb78b447569efb Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Sep 2023 00:45:36 +0900 Subject: [PATCH 03/60] media: apple: isp: Use preallocated heap Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 51 ++++++++++++---------- drivers/media/platform/apple/isp/isp-drv.h | 2 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 3ec7c66b48add5..c11a260246d25b 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -79,30 +79,44 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) static int apple_isp_init_iommu(struct apple_isp *isp) { struct device *dev = isp->dev; - struct isp_firmware *fw = &isp->fw; - u64 heap_base, heap_size, vm_size; + phys_addr_t heap_base; + size_t heap_size; + u64 vm_size; int err; - int i = 0; + int idx; + int size; + struct device_node *mem_node; + const __be32 *maps, *end; isp->domain = iommu_get_domain_for_dev(isp->dev); if (!isp->domain) return -EPROBE_DEFER; isp->shift = __ffs(isp->domain->pgsize_bitmap); - err = of_property_read_u64(dev->of_node, "apple,isp-heap-base", - &heap_base); - if (err) { - dev_err(dev, "failed to read 'apple,isp-heap-base': %d\n", err); - return err; + idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); + mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); + if (!mem_node) { + dev_err(dev, "No memory-region found for heap\n"); + return -ENODEV; } - err = of_property_read_u64(dev->of_node, "apple,isp-heap-size", - &heap_size); - if (err) { - dev_err(dev, "failed to read 'apple,isp-heap-size': %d\n", err); - return err; + maps = of_get_property(mem_node, "iommu-addresses", &size); + if (!maps || !size) { + dev_err(dev, "No valid iommu-addresses found for heap\n"); + return -ENODEV; + } + + end = maps + size / sizeof(__be32); + + while (maps < end) { + maps++; + maps = of_translate_dma_region(dev->of_node, maps, &heap_base, &heap_size); } + printk("heap: 0x%llx 0x%lx\n", heap_base, heap_size); + + isp->fw.heap_top = heap_base + heap_size; + err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", &vm_size); if (err) { @@ -110,15 +124,7 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return err; } - drm_mm_init(&isp->iovad, heap_base, vm_size - heap_base); - - /* Allocate read-only coprocessor private heap */ - fw->heap = isp_alloc_surface(isp, heap_size); - if (!fw->heap) { - drm_mm_takedown(&isp->iovad); - err = -ENOMEM; - return err; - } + drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); apple_isp_iommu_sync_ttbr(isp); @@ -127,7 +133,6 @@ static int apple_isp_init_iommu(struct apple_isp *isp) static void apple_isp_free_iommu(struct apple_isp *isp) { - isp_free_surface(isp, isp->fw.heap); drm_mm_takedown(&isp->iovad); } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 5db64dcc844863..7b463eaef1c9ce 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -196,7 +196,7 @@ struct apple_isp { struct mutex iovad_lock; struct isp_firmware { - struct isp_surf *heap; + u64 heap_top; } fw; struct isp_surf *ipc_surf; From ae2938db2fbb709c79371ccc76a803983eb24dbf Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 8 Sep 2023 00:45:49 +0900 Subject: [PATCH 04/60] media: apple: isp: Fixup shared region arg Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-fw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 3d1e961a1cc262..b3828e9798d4cd 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -29,8 +29,8 @@ static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; - u64 unk_size; - u64 unk_inv; + u64 shared_base; + u64 shared_size; u64 extra_iova; u64 extra_size; u32 unk4; @@ -253,8 +253,8 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; - args.unk_size = 0x1800000; - args.unk_inv = 0x10000000 - args.unk_size; + args.shared_base = isp->fw.heap_top; + args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.unk4 = 0x1; From d0c45533a31dcbe0c28ed622ecdf7fe26f044b96 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 10 Sep 2023 22:57:06 +0900 Subject: [PATCH 05/60] media: apple: isp: Enable t6000 Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index c11a260246d25b..7b851ce444c57f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -353,6 +353,7 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, {}, }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); From 2bcf15401617d6f5be02e10ec8801fae823cf9d7 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Sat, 2 Sep 2023 01:07:08 +0900 Subject: [PATCH 06/60] media: apple: isp: Split gpio/mbox MMIO range Offsets differ across socs. Makes more sense than "core" too. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 12 +++- drivers/media/platform/apple/isp/isp-drv.h | 3 +- drivers/media/platform/apple/isp/isp-fw.c | 76 ++++++++++++--------- drivers/media/platform/apple/isp/isp-ipc.c | 4 +- drivers/media/platform/apple/isp/isp-regs.h | 49 ++++++------- 5 files changed, 75 insertions(+), 69 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 7b851ce444c57f..59aed8c01785ab 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -164,9 +164,15 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } - isp->core = devm_platform_ioremap_resource_byname(pdev, "core"); - if (IS_ERR(isp->core)) { - err = PTR_ERR(isp->core); + isp->mbox = devm_platform_ioremap_resource_byname(pdev, "mbox"); + if (IS_ERR(isp->mbox)) { + err = PTR_ERR(isp->mbox); + goto detach_genpd; + } + + isp->gpio = devm_platform_ioremap_resource_byname(pdev, "gpio"); + if (IS_ERR(isp->gpio)) { + err = PTR_ERR(isp->gpio); goto detach_genpd; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 7b463eaef1c9ce..de9b3fd2def5ee 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -185,7 +185,8 @@ struct apple_isp { int irq; void __iomem *asc; - void __iomem *core; + void __iomem *mbox; + void __iomem *gpio; void __iomem *dart0; void __iomem *dart1; void __iomem *dart2; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index b3828e9798d4cd..743967a8b221d3 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -26,6 +26,16 @@ static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->asc + reg); } +static inline u32 isp_gpio_read32(struct apple_isp *isp, u32 reg) +{ + return readl(isp->gpio + reg); +} + +static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->gpio + reg); +} + struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; @@ -76,8 +86,8 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) { struct apple_isp *isp = dev; - isp_core_write32(isp, ISP_CORE_IRQ_ACK, - isp_core_read32(isp, ISP_CORE_IRQ_INTERRUPT)); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, + isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); wake_up_interruptible_all(&isp->wait); @@ -94,9 +104,9 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) static void isp_disable_irq(struct apple_isp *isp) { - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); free_irq(isp->irq, isp); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0xfeedbabe); /* real funny */ + isp_gpio_write32(isp, ISP_GPIO_1, 0xfeedbabe); /* real funny */ } static int isp_enable_irq(struct apple_isp *isp) @@ -111,7 +121,7 @@ static int isp_enable_irq(struct apple_isp *isp) isp_dbg(isp, "about to enable interrupts...\n"); - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0xf); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0xf); return 0; } @@ -165,26 +175,26 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) if (err < 0) return err; - isp_core_write32(isp, ISP_CORE_CLOCK_EN, 0x1); + isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); - isp_core_write32(isp, ISP_CORE_GPIO_0, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_2, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_3, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_4, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_5, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_6, 0x0); - isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + isp_gpio_write32(isp, ISP_GPIO_0, 0x0); + isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_2, 0x0); + isp_gpio_write32(isp, ISP_GPIO_3, 0x0); + isp_gpio_write32(isp, ISP_GPIO_4, 0x0); + isp_gpio_write32(isp, ISP_GPIO_5, 0x0); + isp_gpio_write32(isp, ISP_GPIO_6, 0x0); + isp_gpio_write32(isp, ISP_GPIO_7, 0x0); - isp_core_write32(isp, ISP_CORE_IRQ_ENABLE, 0x0); + isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); - /* Wait for ISP_CORE_GPIO_7 to 0x0 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_7, 0x0); + /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_7, 0x0); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { isp_dbg(isp, "got first magic number (0x%x) from firmware\n", @@ -215,9 +225,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) dma_addr_t args_iova; int err, retries; - u32 num_ipc_chans = isp_core_read32(isp, ISP_CORE_GPIO_0); - u32 args_offset = isp_core_read32(isp, ISP_CORE_GPIO_1); - u32 extra_size = isp_core_read32(isp, ISP_CORE_GPIO_3); + u32 num_ipc_chans = isp_gpio_read32(isp, ISP_GPIO_0); + u32 args_offset = isp_gpio_read32(isp, ISP_GPIO_1); + u32 extra_size = isp_gpio_read32(isp, ISP_GPIO_3); isp->num_ipc_chans = num_ipc_chans; if (!isp->num_ipc_chans) { @@ -264,14 +274,14 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); - isp_core_write32(isp, ISP_CORE_GPIO_0, args_iova); - isp_core_write32(isp, ISP_CORE_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_0, args_iova); + isp_gpio_write32(isp, ISP_GPIO_1, 0x0); - /* Wait for ISP_CORE_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_7, 0xf7fbdff9); + /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_7); + u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { isp_dbg(isp, "got second magic number (0x%x) from firmware\n", @@ -324,7 +334,7 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { - u32 table_iova = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 table_iova = isp_gpio_read32(isp, ISP_GPIO_0); isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); @@ -416,11 +426,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) } } - /* Wait for ISP_CORE_GPIO_3 to 0x8042006 -> 0x0 */ - isp_core_write32(isp, ISP_CORE_GPIO_3, 0x8042006); + /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ + isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_3); + u32 val = isp_gpio_read32(isp, ISP_GPIO_3); if (val == 0x0) { isp_dbg(isp, "got third magic number (0x%x) from firmware\n", @@ -445,14 +455,14 @@ static int isp_stop_command_processor(struct apple_isp *isp) { int retries; - /* Wait for ISP_CORE_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ - isp_core_write32(isp, ISP_CORE_GPIO_0, 0xf7fbdff9); + /* Wait for ISP_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ + isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); /* Their CISP_CMD_STOP implementation is buggy */ isp_cmd_suspend(isp); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - u32 val = isp_core_read32(isp, ISP_CORE_GPIO_0); + u32 val = isp_gpio_read32(isp, ISP_GPIO_0); if (val == 0x8042006) { isp_dbg(isp, "got magic number (0x%x) from firmware\n", val); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index ef3498c4fcd191..a9a0fdb73a4d9f 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -110,7 +110,7 @@ static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) chan_write_msg(isp, chan, &chan->rsp); - isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); chan_update_cursor(chan); @@ -165,7 +165,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, chan_write_msg(isp, chan, &chan->req); wmb(); - isp_core_write32(isp, ISP_CORE_IRQ_DOORBELL, chan->doorbell); + isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), timeout); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index b9bd505844d9de..e21485ec4ce823 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -23,40 +23,29 @@ #define ISP_ASC_IRQ_MASK_4 0x1400a10 #define ISP_ASC_IRQ_MASK_5 0x1400a14 -#define ISP_CORE_IRQ_INTERRUPT 0x2104000 -#define ISP_CORE_IRQ_ENABLE 0x2104004 -#define ISP_CORE_IRQ_DOORBELL 0x21043f0 -#define ISP_CORE_IRQ_ACK 0x21043fc - -#define ISP_CORE_GPIO_0 0x2104170 -#define ISP_CORE_GPIO_1 0x2104174 -#define ISP_CORE_GPIO_2 0x2104178 -#define ISP_CORE_GPIO_3 0x210417c -#define ISP_CORE_GPIO_4 0x2104180 -#define ISP_CORE_GPIO_5 0x2104184 -#define ISP_CORE_GPIO_6 0x2104188 -#define ISP_CORE_GPIO_7 0x210418c - -#define ISP_CORE_CLOCK_EN 0x2104190 - -#define ISP_CORE_DPE_CTRL_0 0x2504000 -#define ISP_CORE_DPE_CTRL_1 0x2508000 - -static inline u32 isp_core_read32(struct apple_isp *isp, u32 reg) +#define ISP_MBOX_IRQ_INTERRUPT 0x000 +#define ISP_MBOX_IRQ_ENABLE 0x004 +#define ISP_MBOX_IRQ_DOORBELL 0x3f0 +#define ISP_MBOX_IRQ_ACK 0x3fc + +#define ISP_GPIO_0 0x00 +#define ISP_GPIO_1 0x04 +#define ISP_GPIO_2 0x08 +#define ISP_GPIO_3 0x0c +#define ISP_GPIO_4 0x10 +#define ISP_GPIO_5 0x14 +#define ISP_GPIO_6 0x18 +#define ISP_GPIO_7 0x1c +#define ISP_GPIO_CLOCK_EN 0x20 + +static inline u32 isp_mbox_read32(struct apple_isp *isp, u32 reg) { - return readl(isp->core + reg - 0x2104000); // TODO this sucks + return readl(isp->mbox + reg); } -static inline void isp_core_write32(struct apple_isp *isp, u32 reg, u32 val) +static inline void isp_mbox_write32(struct apple_isp *isp, u32 reg, u32 val) { - writel(val, isp->core + reg - 0x2104000); -} - -static inline void isp_core_mask32(struct apple_isp *isp, u32 reg, u32 clear, - u32 set) -{ - isp_core_write32(isp, reg, isp_core_read32(isp, reg) & ~clear); - isp_core_write32(isp, reg, isp_core_read32(isp, reg) | set); + writel(val, isp->mbox + reg); } #endif /* __ISP_REGS_H__ */ From 0527c0feebb6cf88cfc85bc344a2d651aa929255 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 10 Sep 2023 23:36:12 +0900 Subject: [PATCH 07/60] media: apple: isp: Drop the DART mirroring stuff Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 57 -------------------- drivers/media/platform/apple/isp/isp-drv.h | 8 --- drivers/media/platform/apple/isp/isp-iommu.c | 19 ------- drivers/media/platform/apple/isp/isp-iommu.h | 3 -- 4 files changed, 87 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 59aed8c01785ab..1227c8b4eeffd2 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -126,8 +126,6 @@ static int apple_isp_init_iommu(struct apple_isp *isp) drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); - apple_isp_iommu_sync_ttbr(isp); - return 0; } @@ -140,7 +138,6 @@ static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct apple_isp *isp; - struct resource *res; int err; isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); @@ -176,31 +173,6 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dart0"); - if (!res) { - err = -ENODEV; - goto detach_genpd; - } - - /* Simply ioremap since it's a shared register zone */ - isp->dart0 = devm_ioremap(dev, res->start, resource_size(res)); - if (IS_ERR(isp->dart0)) { - err = PTR_ERR(isp->dart0); - goto detach_genpd; - } - - isp->dart1 = devm_platform_ioremap_resource_byname(pdev, "dart1"); - if (IS_ERR(isp->dart1)) { - err = PTR_ERR(isp->dart1); - goto detach_genpd; - } - - isp->dart2 = devm_platform_ioremap_resource_byname(pdev, "dart2"); - if (IS_ERR(isp->dart2)) { - err = PTR_ERR(isp->dart2); - goto detach_genpd; - } - isp->irq = platform_get_irq(pdev, 0); if (isp->irq < 0) { err = isp->irq; @@ -270,12 +242,6 @@ static int apple_isp_remove(struct platform_device *pdev) return 0; } -/* T8020/T6000 registers */ -#define DART_T8020_STREAM_COMMAND 0x20 -#define DART_T8020_STREAM_SELECT 0x34 -#define DART_T8020_TTBR 0x200 -#define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20) - static const struct apple_isp_hw apple_isp_hw_t8103 = { .pmu_base = 0x23b704000, @@ -296,11 +262,6 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_base = 0x23bc3c000, .bandwidth_bit = 0x0, .bandwidth_size = 0x4, - - .stream_command = DART_T8020_STREAM_COMMAND, - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct apple_isp_hw apple_isp_hw_t6000 = { @@ -323,11 +284,6 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - - .stream_command = DART_T8020_STREAM_COMMAND, - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct apple_isp_hw apple_isp_hw_t8110 = { @@ -350,11 +306,6 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - - .stream_command = DART_T8020_STREAM_COMMAND, // TODO - .stream_select = DART_T8020_STREAM_SELECT, - .ttbr = DART_T8020_TTBR, - .stream_command_invalidate = DART_T8020_STREAM_COMMAND_INVALIDATE, }; static const struct of_device_id apple_isp_of_match[] = { @@ -366,19 +317,11 @@ MODULE_DEVICE_TABLE(of, apple_isp_of_match); static __maybe_unused int apple_isp_suspend(struct device *dev) { - struct apple_isp *isp = dev_get_drvdata(dev); - - apple_isp_iommu_invalidate_tlb(isp); - return 0; } static __maybe_unused int apple_isp_resume(struct device *dev) { - struct apple_isp *isp = dev_get_drvdata(dev); - - apple_isp_iommu_sync_ttbr(isp); - return 0; } DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index de9b3fd2def5ee..bf3824cc0636b9 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -82,11 +82,6 @@ struct apple_isp_hw { u64 bandwidth_base; u8 bandwidth_bit; u8 bandwidth_size; - - u32 stream_command; - u32 stream_select; - u32 ttbr; - u32 stream_command_invalidate; }; struct isp_resv { @@ -187,9 +182,6 @@ struct apple_isp { void __iomem *asc; void __iomem *mbox; void __iomem *gpio; - void __iomem *dart0; - void __iomem *dart1; - void __iomem *dart2; struct iommu_domain *domain; unsigned long shift; diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index ede4fe8e226913..7a7f24aa0174ba 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -5,23 +5,6 @@ #include "isp-iommu.h" -void apple_isp_iommu_sync_ttbr(struct apple_isp *isp) -{ - writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart1 + isp->hw->ttbr); - writel(readl(isp->dart0 + isp->hw->ttbr), isp->dart2 + isp->hw->ttbr); -} - -void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp) -{ - iommu_flush_iotlb_all(isp->domain); - writel(0x1, isp->dart1 + isp->hw->stream_select); - writel(isp->hw->stream_command_invalidate, - isp->dart1 + isp->hw->stream_command); - writel(0x1, isp->dart2 + isp->hw->stream_select); - writel(isp->hw->stream_command_invalidate, - isp->dart2 + isp->hw->stream_command); -} - static void isp_surf_free_pages(struct isp_surf *surf) { for (u32 i = 0; i < surf->num_pages && surf->pages[i] != NULL; i++) { @@ -112,7 +95,6 @@ static int isp_surf_reserve_iova(struct apple_isp *isp, struct isp_surf *surf) static void isp_surf_iommu_unmap(struct apple_isp *isp, struct isp_surf *surf) { iommu_unmap(isp->domain, surf->iova, surf->size); - apple_isp_iommu_invalidate_tlb(isp); sg_free_table(&surf->sgt); } @@ -269,6 +251,5 @@ int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, void apple_isp_iommu_unmap_sgt(struct apple_isp *isp, struct isp_surf *surf) { iommu_unmap(isp->domain, surf->iova, surf->size); - apple_isp_iommu_invalidate_tlb(isp); isp_surf_unreserve_iova(isp, surf); } diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h index f9972bd9ff93e7..326cf7c12aa745 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.h +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -6,9 +6,6 @@ #include "isp-drv.h" -void apple_isp_iommu_sync_ttbr(struct apple_isp *isp); -void apple_isp_iommu_invalidate_tlb(struct apple_isp *isp); - struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); #define isp_alloc_surface(isp, size) (__isp_alloc_surface(isp, size, false)) #define isp_alloc_surface_gc(isp, size) (__isp_alloc_surface(isp, size, true)) From 26f0569a53c057f5b7c54c7794476a2255d3e3b1 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 11 Sep 2023 00:12:11 +0900 Subject: [PATCH 08/60] media: apple: isp: Do not defer on failure to initialize DART This can fail for non-DEFER reasons. If this can happen due to probe defers, we need to figure out some way to signal that specifically... Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 1227c8b4eeffd2..f1ce1a7986ebd4 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -90,7 +90,7 @@ static int apple_isp_init_iommu(struct apple_isp *isp) isp->domain = iommu_get_domain_for_dev(isp->dev); if (!isp->domain) - return -EPROBE_DEFER; + return -ENODEV; isp->shift = __ffs(isp->domain->pgsize_bitmap); idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); From baee2ca3816c8d61ab212a9834e51b9212b7efcf Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Mon, 11 Sep 2023 02:06:05 +0900 Subject: [PATCH 09/60] media: apple: WIP: t6000 hax --- drivers/media/platform/apple/isp/isp-cam.c | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index bb90337cb7c19f..74125b3c652433 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -207,7 +207,7 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) args, sizeof(*args), false); err = isp_ch_get_sensor_id(isp, ch); - if (err || (fmt->id != ISP_IMX248_1820_01)) { + if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { dev_err(isp->dev, "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", ch); diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 743967a8b221d3..41f78aa71ba421 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -267,8 +267,12 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.unk4 = 0x1; + args.unk4 = 0x3; + //args.pad_40[1] = 0x3128000; + //args.pad_40[3] = 0x48000; + args.pad_40[5] = 0x90; args.unk5 = 0x40; + //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; args.unk9 = 0x3; From 9359bfaa521811df790974959b3ced1d11e609cf Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 17:58:26 +0900 Subject: [PATCH 10/60] media: apple: isp: Set platform_id in bootargs Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 3 +++ drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 5 ++--- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index f1ce1a7986ebd4..438885798a5975 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -243,6 +243,7 @@ static int apple_isp_remove(struct platform_device *pdev) } static const struct apple_isp_hw apple_isp_hw_t8103 = { + .platform_id = 0x1, .pmu_base = 0x23b704000, .dsid_clr_base0 = 0x200014000, @@ -265,6 +266,7 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { }; static const struct apple_isp_hw apple_isp_hw_t6000 = { + .platform_id = 0x3, .pmu_base = 0x28e584000, .dsid_clr_base0 = 0x200014000, @@ -287,6 +289,7 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { }; static const struct apple_isp_hw apple_isp_hw_t8110 = { + .platform_id = 0xe, // J413AP .pmu_base = 0x23b704000, .dsid_clr_base0 = 0x200014000, // TODO diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index bf3824cc0636b9..fb7a785b87c1c5 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -63,6 +63,7 @@ struct isp_channel { }; struct apple_isp_hw { + u32 platform_id; u64 pmu_base; u64 dsid_clr_base0; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 41f78aa71ba421..3050cf68d75c69 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -43,7 +43,7 @@ struct isp_firmware_bootargs { u64 shared_size; u64 extra_iova; u64 extra_size; - u32 unk4; + u32 platform_id; u32 pad_40[7]; u32 ipc_size; u32 pad_60[5]; @@ -267,10 +267,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000 - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.unk4 = 0x3; + args.platform_id = isp->hw->platform_id; //args.pad_40[1] = 0x3128000; //args.pad_40[3] = 0x48000; - args.pad_40[5] = 0x90; args.unk5 = 0x40; //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; From 275b3b7597cf0f0e03daca2456a3513d7b47c48f Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 18:49:25 +0900 Subject: [PATCH 11/60] media: apple: isp: Better document info struct fields "Document". I also counted wrong multiple times. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-cmd.h | 64 +++++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index dde6aad506c23e..1fc484fa687853 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -202,19 +202,53 @@ static_assert(sizeof(struct cmd_ch_stop) == 0xc); struct cmd_ch_info { u64 opcode; u32 chan; - u32 unk_c; - u32 unk_10[4]; + u32 unk_c; // 0x7da0001, 0x7db0001 + u32 unk_10; // 0x300ac, 0x5006d + u32 unk_14; // 0x40007, 0x10007 + u32 unk_18; // 0x5, 0x2 + u32 unk_1c; // 0x1, 0x1 u32 version; - u32 unk_24[3]; - u32 unk_30[12]; + u32 unk_24; // 0x7, 0x9 + u32 unk_28; // 0x1, 0x1410 + u32 unk_2c; // 0x7, 0x2 + u32 pad_30[7]; + u32 unk_4c; // 0x10000, 0x50000 + u32 unk_50; // 0x1, 0x1 + u32 unk_54; // 0x0, 0x0 + u32 unk_58; // 0x4, 0x4 + u32 unk_5c; // 0x10, 0x20 u32 num_presets; - u32 unk_64[7]; - u32 unk_80[6]; - u32 unk_98_freq; + u32 unk_64; // 0x0, 0x0 + u32 unk_68; // 0x44c0, 0x4680 + u32 unk_6c; // 0x40, 0x40 + u32 unk_70; // 0x1, 0x1 + u32 unk_74; // 0x2, 0x2 + u32 unk_78; // 0x4000, 0x4000 + u32 unk_7c; // 0x40, 0x40 + u32 unk_80; // 0x1, 0x1 + u32 pad_84[2]; + u32 unk_8c; // 0x36, 0x36 + u32 pad_90[2]; + u32 timestamp_freq; u16 pad_9c; char module_sn[20]; u16 pad_b0; - u32 unk_b4[25]; + u32 unk_b4; // 0x8, 0x8 + u32 pad_b8[2]; + u32 unk_c0; // 0x4, 0x1 + u32 unk_c4; // 0x0, 0x0 + u32 unk_c8; // 0x0, 0x100 + u32 pad_cc[4]; + u32 unk_dc; // 0xff0000, 0xff0000 + u32 unk_e0; // 0xc00, 0xc00 + u32 unk_e4; // 0x0, 0x0 + u32 unk_e8; // 0x1c, 0x1c + u32 unk_ec; // 0x640, 0x680 + u32 unk_f0; // 0x4, 0x4 + u32 unk_f4; // 0x4, 0x4 + u32 pad_f8[6]; + u32 unk_110; // 0x0, 0x7800000 + u32 unk_114; // 0x0, 0x780 } __packed; static_assert(sizeof(struct cmd_ch_info) == 0x118); @@ -226,7 +260,19 @@ struct cmd_ch_camera_config { u16 in_height; u16 out_width; u16 out_height; - u32 unk[49]; + u32 unk_28; + u32 unk_2c; + u32 unk_30[16]; + u32 sensor_clk; + u32 unk_64[4]; + u32 timestamp_freq; + u32 unk_78[2]; + u32 unk_80[16]; + u32 in_width2; // repeated in u32?? + u32 in_height2; + u32 unk_c8[3]; + u32 out_width2; + u32 out_height2; } __packed; static_assert(sizeof(struct cmd_ch_camera_config) == 0xdc); From 0282fb723f43aeaed3fa89031ae7536c6b528127 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 19:44:52 +0900 Subject: [PATCH 12/60] media: apple: isp: Don't use define for bootargs size Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 3050cf68d75c69..cf7615d451f45f 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -12,7 +12,6 @@ #define ISP_FIRMWARE_MDELAY 1 #define ISP_FIRMWARE_MAX_TRIES 1000 -#define ISP_FIRMWARE_BOOTARGS_SIZE 0x180 #define ISP_FIRMWARE_IPC_SIZE 0x1c000 #define ISP_FIRMWARE_DATA_SIZE 0x28000 @@ -56,8 +55,7 @@ struct isp_firmware_bootargs { u32 pad_c0[47]; u32 unk9; } __packed; -static_assert(sizeof(struct isp_firmware_bootargs) == - ISP_FIRMWARE_BOOTARGS_SIZE); +static_assert(sizeof(struct isp_firmware_bootargs) == 0x180); struct isp_chan_desc { char name[64]; @@ -273,7 +271,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk5 = 0x40; //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; - args.unk_iova1 = args_iova + ISP_FIRMWARE_BOOTARGS_SIZE - 0xc; + args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); From 983d606308875425ed48135f39914083fcaacd5a Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 19:53:11 +0900 Subject: [PATCH 13/60] media: apple: isp: wmb() before GPIO write Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index cf7615d451f45f..d616eee97c778e 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -277,6 +277,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); From ed0d9d37e4166cb7653db0d0c8f3b0945b67c1a8 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 12 Sep 2023 20:05:34 +0900 Subject: [PATCH 14/60] media: apple: isp: s/asc/coproc/ Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 6 +-- drivers/media/platform/apple/isp/isp-drv.h | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 46 ++++++++++----------- drivers/media/platform/apple/isp/isp-regs.h | 32 +++++++------- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 438885798a5975..e0efbeb4880ceb 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -155,9 +155,9 @@ static int apple_isp_probe(struct platform_device *pdev) return err; } - isp->asc = devm_platform_ioremap_resource_byname(pdev, "asc"); - if (IS_ERR(isp->asc)) { - err = PTR_ERR(isp->asc); + isp->coproc = devm_platform_ioremap_resource_byname(pdev, "coproc"); + if (IS_ERR(isp->coproc)) { + err = PTR_ERR(isp->coproc); goto detach_genpd; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index fb7a785b87c1c5..ed567c06d8dccf 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -180,7 +180,7 @@ struct apple_isp { int irq; - void __iomem *asc; + void __iomem *coproc; void __iomem *mbox; void __iomem *gpio; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index d616eee97c778e..506c0946222350 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -9,20 +9,20 @@ #include "isp-ipc.h" #include "isp-regs.h" -#define ISP_FIRMWARE_MDELAY 1 -#define ISP_FIRMWARE_MAX_TRIES 1000 +#define ISP_FIRMWARE_MDELAY 1 +#define ISP_FIRMWARE_MAX_TRIES 1000 -#define ISP_FIRMWARE_IPC_SIZE 0x1c000 -#define ISP_FIRMWARE_DATA_SIZE 0x28000 +#define ISP_FIRMWARE_IPC_SIZE 0x1c000 +#define ISP_FIRMWARE_DATA_SIZE 0x28000 -static inline u32 isp_asc_read32(struct apple_isp *isp, u32 reg) +static inline u32 isp_coproc_read32(struct apple_isp *isp, u32 reg) { - return readl(isp->asc + reg); + return readl(isp->coproc + reg); } -static inline void isp_asc_write32(struct apple_isp *isp, u32 reg, u32 val) +static inline void isp_coproc_write32(struct apple_isp *isp, u32 reg, u32 val) { - writel(val, isp->asc + reg); + writel(val, isp->coproc + reg); } static inline u32 isp_gpio_read32(struct apple_isp *isp, u32 reg) @@ -129,22 +129,22 @@ static int isp_coproc_ready(struct apple_isp *isp) int retries; u32 status; - isp_asc_write32(isp, ISP_ASC_EDPRCR, 0x2); + isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); - isp_asc_write32(isp, ISP_ASC_PMGR_0, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_1, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_2, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_PMGR_3, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_0, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_1, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_2, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_PMGR_3, 0xff00ff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_0, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_1, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_2, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_3, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_4, 0xffffffff); - isp_asc_write32(isp, ISP_ASC_IRQ_MASK_5, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_0, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_1, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_2, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_3, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_4, 0xffffffff); + isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_5, 0xffffffff); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { - status = isp_asc_read32(isp, ISP_ASC_STATUS); + status = isp_coproc_read32(isp, ISP_COPROC_STATUS); if (!((status & 0x3) == 0)) { isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", retries, status); @@ -162,7 +162,7 @@ static int isp_coproc_ready(struct apple_isp *isp) static void isp_firmware_shutdown_stage1(struct apple_isp *isp) { - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); } static int isp_firmware_boot_stage1(struct apple_isp *isp) @@ -186,8 +186,8 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_mbox_write32(isp, ISP_MBOX_IRQ_ENABLE, 0x0); - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x0); - isp_asc_write32(isp, ISP_ASC_CONTROL, 0x10); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); + isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x10); /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0x0); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index e21485ec4ce823..b3032e9112c012 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -6,22 +6,22 @@ #include "isp-drv.h" -#define ISP_ASC_PMGR_0 0x738 -#define ISP_ASC_PMGR_1 0x798 -#define ISP_ASC_PMGR_2 0x7f8 -#define ISP_ASC_PMGR_3 0x858 - -#define ISP_ASC_RVBAR 0x1050000 -#define ISP_ASC_EDPRCR 0x1010310 -#define ISP_ASC_CONTROL 0x1400044 -#define ISP_ASC_STATUS 0x1400048 - -#define ISP_ASC_IRQ_MASK_0 0x1400a00 -#define ISP_ASC_IRQ_MASK_1 0x1400a04 -#define ISP_ASC_IRQ_MASK_2 0x1400a08 -#define ISP_ASC_IRQ_MASK_3 0x1400a0c -#define ISP_ASC_IRQ_MASK_4 0x1400a10 -#define ISP_ASC_IRQ_MASK_5 0x1400a14 +#define ISP_COPROC_PMGR_0 0x738 +#define ISP_COPROC_PMGR_1 0x798 +#define ISP_COPROC_PMGR_2 0x7f8 +#define ISP_COPROC_PMGR_3 0x858 + +#define ISP_COPROC_RVBAR 0x1050000 +#define ISP_COPROC_EDPRCR 0x1010310 +#define ISP_COPROC_CONTROL 0x1400044 +#define ISP_COPROC_STATUS 0x1400048 + +#define ISP_COPROC_IRQ_MASK_0 0x1400a00 +#define ISP_COPROC_IRQ_MASK_1 0x1400a04 +#define ISP_COPROC_IRQ_MASK_2 0x1400a08 +#define ISP_COPROC_IRQ_MASK_3 0x1400a0c +#define ISP_COPROC_IRQ_MASK_4 0x1400a10 +#define ISP_COPROC_IRQ_MASK_5 0x1400a14 #define ISP_MBOX_IRQ_INTERRUPT 0x000 #define ISP_MBOX_IRQ_ENABLE 0x004 From a78777c70e496e61dfa667d57fd3e9eb86851a9b Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 18:26:09 +0900 Subject: [PATCH 15/60] media: apple: isp: rm unused bootargs members Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 506c0946222350..df0554599ffae2 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -266,10 +266,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; - //args.pad_40[1] = 0x3128000; - //args.pad_40[3] = 0x48000; args.unk5 = 0x40; - //args.pad_7c[3] = 0x3b54000; args.unk7 = 0x1; args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; From 8739cbb118bacd53ad692c2d5b72a3ef3a8843c1 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 19:17:46 +0900 Subject: [PATCH 16/60] media: apple: isp: rm old isp_resv struct Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index ed567c06d8dccf..e672c62c0ec41c 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -85,12 +85,6 @@ struct apple_isp_hw { u8 bandwidth_size; }; -struct isp_resv { - phys_addr_t phys; - dma_addr_t iova; - u64 size; -}; - enum isp_sensor_id { ISP_IMX248_1820_01, ISP_IMX248_1822_02, From 3cecdc2b2142e16cf36252858c2b93f8d36509d5 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 19:32:24 +0900 Subject: [PATCH 17/60] media: apple: isp: misc isp-fw.c improvements Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-fw.c | 19 +++++++++++-------- drivers/media/platform/apple/isp/isp-regs.h | 8 ++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index df0554599ffae2..61b2431d8c5f43 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -15,6 +15,8 @@ #define ISP_FIRMWARE_IPC_SIZE 0x1c000 #define ISP_FIRMWARE_DATA_SIZE 0x28000 +#define ISP_COPROC_IN_WFI 0x3 + static inline u32 isp_coproc_read32(struct apple_isp *isp, u32 reg) { return readl(isp->coproc + reg); @@ -124,17 +126,17 @@ static int isp_enable_irq(struct apple_isp *isp) return 0; } -static int isp_coproc_ready(struct apple_isp *isp) +static int isp_reset_coproc(struct apple_isp *isp) { int retries; u32 status; isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); - isp_coproc_write32(isp, ISP_COPROC_PMGR_0, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_1, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_2, 0xff00ff); - isp_coproc_write32(isp, ISP_COPROC_PMGR_3, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_0, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_1, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_2, 0xff00ff); + isp_coproc_write32(isp, ISP_COPROC_FABRIC_3, 0xff00ff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_0, 0xffffffff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_1, 0xffffffff); @@ -145,7 +147,7 @@ static int isp_coproc_ready(struct apple_isp *isp) for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { status = isp_coproc_read32(isp, ISP_COPROC_STATUS); - if (!((status & 0x3) == 0)) { + if (status & ISP_COPROC_IN_WFI) { isp_dbg(isp, "%d: coproc in WFI (status: 0x%x)\n", retries, status); break; @@ -169,7 +171,7 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; - err = isp_coproc_ready(isp); + err = isp_reset_coproc(isp); if (err < 0) return err; @@ -262,7 +264,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; args.shared_base = isp->fw.heap_top; - args.shared_size = 0x10000000 - isp->fw.heap_top; + args.shared_size = 0x10000000UL - isp->fw.heap_top; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; @@ -424,6 +426,7 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); } } + wmb(); /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index b3032e9112c012..3a99229f6d4c8f 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -6,10 +6,10 @@ #include "isp-drv.h" -#define ISP_COPROC_PMGR_0 0x738 -#define ISP_COPROC_PMGR_1 0x798 -#define ISP_COPROC_PMGR_2 0x7f8 -#define ISP_COPROC_PMGR_3 0x858 +#define ISP_COPROC_FABRIC_0 0x738 +#define ISP_COPROC_FABRIC_1 0x798 +#define ISP_COPROC_FABRIC_2 0x7f8 +#define ISP_COPROC_FABRIC_3 0x858 #define ISP_COPROC_RVBAR 0x1050000 #define ISP_COPROC_EDPRCR 0x1010310 From de3f018ef8d9d41c4a2427b84a77aeadc4457211 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 20:06:55 +0900 Subject: [PATCH 18/60] media: apple: isp: alloc static surfaces only once Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 16 ++++++-- drivers/media/platform/apple/isp/isp-fw.c | 47 +++++++++++++--------- drivers/media/platform/apple/isp/isp-fw.h | 3 ++ 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index e0efbeb4880ceb..c52148f4a08ed3 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -19,6 +19,7 @@ #include #include "isp-cam.h" +#include "isp-fw.h" #include "isp-iommu.h" #include "isp-v4l2.h" @@ -202,26 +203,34 @@ static int apple_isp_probe(struct platform_device *pdev) goto destroy_wq; } + err = apple_isp_alloc_firmware_surface(isp); + if (err) { + dev_err(dev, "failed to alloc firmware surface: %d\n", err); + goto free_iommu; + } + pm_runtime_enable(dev); err = apple_isp_detect_camera(isp); if (err) { dev_err(dev, "failed to detect camera: %d\n", err); - goto free_iommu; + goto free_surface; } err = apple_isp_setup_video(isp); if (err) { dev_err(dev, "failed to register video device: %d\n", err); - goto free_iommu; + goto free_surface; } dev_info(dev, "apple-isp probe!\n"); return 0; -free_iommu: +free_surface: pm_runtime_disable(dev); + apple_isp_free_firmware_surface(isp); +free_iommu: apple_isp_free_iommu(isp); destroy_wq: destroy_workqueue(isp->wq); @@ -236,6 +245,7 @@ static int apple_isp_remove(struct platform_device *pdev) apple_isp_remove_video(isp); pm_runtime_disable(isp->dev); + apple_isp_free_firmware_surface(isp); apple_isp_free_iommu(isp); destroy_workqueue(isp->wq); apple_isp_detach_genpd(isp); diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 61b2431d8c5f43..cb3ef268daf248 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -212,13 +212,36 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) return 0; } -static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +int apple_isp_alloc_firmware_surface(struct apple_isp *isp) +{ + /* These are static, so let's do it once and for all */ + isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); + if (!isp->ipc_surf) { + isp_err(isp, "failed to alloc shared surface for ipc\n"); + return -ENOMEM; + } + + isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); + if (!isp->data_surf) { + isp_err(isp, "failed to alloc shared surface for data files\n"); + isp_free_surface(isp, isp->ipc_surf); + return -ENOMEM; + } + + return 0; +} + +void apple_isp_free_firmware_surface(struct apple_isp *isp) { isp_free_surface(isp, isp->data_surf); - isp_free_surface(isp, isp->extra_surf); isp_free_surface(isp, isp->ipc_surf); } +static void isp_firmware_shutdown_stage2(struct apple_isp *isp) +{ + isp_free_surface(isp, isp->extra_surf); +} + static int isp_firmware_boot_stage2(struct apple_isp *isp) { struct isp_firmware_bootargs args; @@ -239,22 +262,10 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) dev_warn(isp->dev, "unexpected channel count (%d)\n", num_ipc_chans); - isp->ipc_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_IPC_SIZE); - if (!isp->ipc_surf) { - isp_err(isp, "failed to alloc surface for ipc\n"); - return -ENOMEM; - } - isp->extra_surf = isp_alloc_surface_vmap(isp, extra_size); if (!isp->extra_surf) { isp_err(isp, "failed to alloc surface for extra heap\n"); - goto free_ipc; - } - - isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); - if (!isp->data_surf) { - isp_err(isp, "failed to alloc surface for data files\n"); - goto free_extra; + return -ENOMEM; } args_iova = isp->ipc_surf->iova + args_offset + 0x40; @@ -295,17 +306,13 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_err(isp, "never received second magic number from firmware\n"); err = -ENODEV; - goto free_file; + goto free_extra; } return 0; -free_file: - isp_free_surface(isp, isp->data_surf); free_extra: isp_free_surface(isp, isp->extra_surf); -free_ipc: - isp_free_surface(isp, isp->ipc_surf); return err; } diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h index ad9f4fdf641aaa..264717793cea02 100644 --- a/drivers/media/platform/apple/isp/isp-fw.h +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -6,6 +6,9 @@ #include "isp-drv.h" +int apple_isp_alloc_firmware_surface(struct apple_isp *isp); +void apple_isp_free_firmware_surface(struct apple_isp *isp); + int apple_isp_firmware_boot(struct apple_isp *isp); void apple_isp_firmware_shutdown(struct apple_isp *isp); From aed13ad3d4c8912646a31ec49e3988fe31bcccb7 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Thu, 14 Sep 2023 20:32:02 +0900 Subject: [PATCH 19/60] media: apple: isp: fix copyright Not really anymore. Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index c52148f4a08ed3..0c8fb7f5a5473e 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -3,10 +3,6 @@ * Apple Image Signal Processor driver * * Copyright (C) 2023 The Asahi Linux Contributors - * - * Based on aspeed/aspeed-video.c - * Copyright 2020 IBM Corp. - * Copyright (c) 2019-2020 Intel Corporation */ #include From 8a4978c467273bf0a48bcf223741f9b2652f7201 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:01:59 +0900 Subject: [PATCH 20/60] media: apple: isp: Support >32bit VAs for t602x Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 7 ++++++- drivers/media/platform/apple/isp/isp-fw.c | 9 +++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 0c8fb7f5a5473e..f759fda4e0805e 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -121,7 +121,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return err; } - drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - heap_base); + // FIXME: refactor this, maybe use regular iova stuff? + drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - (heap_base & 0xffffffff)); return 0; } @@ -137,6 +138,10 @@ static int apple_isp_probe(struct platform_device *pdev) struct apple_isp *isp; int err; + err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(42)); + if (err) + return err; + isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL); if (!isp) return -ENOMEM; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index cb3ef268daf248..bf06f6b3d4017d 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -274,8 +274,8 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; args.ipc_size = isp->ipc_surf->size; - args.shared_base = isp->fw.heap_top; - args.shared_size = 0x10000000UL - isp->fw.heap_top; + args.shared_base = isp->fw.heap_top & 0xffffffff; + args.shared_size = 0x10000000UL - args.shared_base; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; args.platform_id = isp->hw->platform_id; @@ -286,7 +286,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_iowrite(isp, args_iova, &args, sizeof(args)); isp_gpio_write32(isp, ISP_GPIO_0, args_iova); - isp_gpio_write32(isp, ISP_GPIO_1, 0x0); + isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ @@ -342,7 +342,8 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { - u32 table_iova = isp_gpio_read32(isp, ISP_GPIO_0); + u64 table_iova = isp_gpio_read32(isp, ISP_GPIO_0) | + ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); From d211b34c1f83dfc15913fd9482e3664d179ab4b6 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:02:41 +0900 Subject: [PATCH 21/60] media: apple: isp: t602x hw config Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index f759fda4e0805e..cad201a62b8434 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -322,9 +322,33 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_size = 0x8, }; +static const struct apple_isp_hw apple_isp_hw_t6020 = { + .platform_id = 0x7, // J416cAP + .pmu_base = 0x290284000, + + .dsid_clr_base0 = 0x200014000, // TODO + .dsid_clr_base1 = 0x200054000, + .dsid_clr_base2 = 0x200094000, + .dsid_clr_base3 = 0x2000d4000, + .dsid_clr_range0 = 0x1000, + .dsid_clr_range1 = 0x1000, + .dsid_clr_range2 = 0x1000, + .dsid_clr_range3 = 0x1000, + + .clock_scratch = 0x28e3d0868, // CHECK + .clock_base = 0x0, + .clock_bit = 0x0, + .clock_size = 0x8, + .bandwidth_scratch = 0x28e3d0980, // CHECK + .bandwidth_base = 0x0, + .bandwidth_bit = 0x0, + .bandwidth_size = 0x8, +}; + static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, + { .compatible = "apple,t6020-isp", .data = &apple_isp_hw_t6020 }, {}, }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); From bbcccf920ba686b404b8c930967e725e8f7a5e6a Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sun, 24 Sep 2023 01:03:11 +0900 Subject: [PATCH 22/60] media: apple: isp: Working t602x and multiple formats and more fixes Sorry for the horrible big commit... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 256 ++++++-------- drivers/media/platform/apple/isp/isp-cmd.c | 94 +++++- drivers/media/platform/apple/isp/isp-cmd.h | 106 +++++- drivers/media/platform/apple/isp/isp-drv.c | 153 +++++++-- drivers/media/platform/apple/isp/isp-drv.h | 43 ++- drivers/media/platform/apple/isp/isp-fw.c | 30 +- drivers/media/platform/apple/isp/isp-ipc.c | 9 +- drivers/media/platform/apple/isp/isp-v4l2.c | 349 ++++++++++++++------ 8 files changed, 706 insertions(+), 334 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 74125b3c652433..593b780ab73b15 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -8,6 +8,8 @@ #include "isp-fw.h" #include "isp-iommu.h" +#define ISP_MAX_PRESETS 32 + struct isp_setfile { u32 version; u32 magic; @@ -15,74 +17,56 @@ struct isp_setfile { size_t size; }; -struct isp_preset { - u32 index; - u32 width; - u32 height; - u32 x1; - u32 y1; - u32 x2; - u32 y2; - u32 orig_width; - u32 orig_height; -}; - // clang-format off static const struct isp_setfile isp_setfiles[] = { - [ISP_IMX248_1820_01] = {0x248, 0x18200103, "isp/1820_01XX.dat", 0x442c}, - [ISP_IMX248_1822_02] = {0x248, 0x18220201, "isp/1822_02XX.dat", 0x442c}, - [ISP_IMX343_5221_02] = {0x343, 0x52210211, "isp/5221_02XX.dat", 0x4870}, - [ISP_IMX354_9251_02] = {0x354, 0x92510208, "isp/9251_02XX.dat", 0xa5ec}, - [ISP_IMX356_4820_01] = {0x356, 0x48200107, "isp/4820_01XX.dat", 0x9324}, - [ISP_IMX356_4820_02] = {0x356, 0x48200206, "isp/4820_02XX.dat", 0x9324}, - [ISP_IMX364_8720_01] = {0x364, 0x87200103, "isp/8720_01XX.dat", 0x36ac}, - [ISP_IMX364_8723_01] = {0x364, 0x87230101, "isp/8723_01XX.dat", 0x361c}, - [ISP_IMX372_3820_01] = {0x372, 0x38200108, "isp/3820_01XX.dat", 0xfdb0}, - [ISP_IMX372_3820_02] = {0x372, 0x38200205, "isp/3820_02XX.dat", 0xfdb0}, - [ISP_IMX372_3820_11] = {0x372, 0x38201104, "isp/3820_11XX.dat", 0xfdb0}, - [ISP_IMX372_3820_12] = {0x372, 0x38201204, "isp/3820_12XX.dat", 0xfdb0}, - [ISP_IMX405_9720_01] = {0x405, 0x97200102, "isp/9720_01XX.dat", 0x92c8}, - [ISP_IMX405_9721_01] = {0x405, 0x97210102, "isp/9721_01XX.dat", 0x9818}, - [ISP_IMX405_9723_01] = {0x405, 0x97230101, "isp/9723_01XX.dat", 0x92c8}, - [ISP_IMX414_2520_01] = {0x414, 0x25200102, "isp/2520_01XX.dat", 0xa444}, - [ISP_IMX503_7820_01] = {0x503, 0x78200109, "isp/7820_01XX.dat", 0xb268}, - [ISP_IMX503_7820_02] = {0x503, 0x78200206, "isp/7820_02XX.dat", 0xb268}, - [ISP_IMX505_3921_01] = {0x505, 0x39210102, "isp/3921_01XX.dat", 0x89b0}, - [ISP_IMX514_2820_01] = {0x514, 0x28200108, "isp/2820_01XX.dat", 0xa198}, - [ISP_IMX514_2820_02] = {0x514, 0x28200205, "isp/2820_02XX.dat", 0xa198}, - [ISP_IMX514_2820_03] = {0x514, 0x28200305, "isp/2820_03XX.dat", 0xa198}, - [ISP_IMX514_2820_04] = {0x514, 0x28200405, "isp/2820_04XX.dat", 0xa198}, - [ISP_IMX558_1921_01] = {0x558, 0x19210106, "isp/1921_01XX.dat", 0xad40}, - [ISP_IMX558_1922_02] = {0x558, 0x19220201, "isp/1922_02XX.dat", 0xad40}, - [ISP_IMX603_7920_01] = {0x603, 0x79200109, "isp/7920_01XX.dat", 0xad2c}, - [ISP_IMX603_7920_02] = {0x603, 0x79200205, "isp/7920_02XX.dat", 0xad2c}, - [ISP_IMX603_7921_01] = {0x603, 0x79210104, "isp/7921_01XX.dat", 0xad90}, - [ISP_IMX613_4920_01] = {0x613, 0x49200108, "isp/4920_01XX.dat", 0x9324}, - [ISP_IMX613_4920_02] = {0x613, 0x49200204, "isp/4920_02XX.dat", 0x9324}, - [ISP_IMX614_2921_01] = {0x614, 0x29210107, "isp/2921_01XX.dat", 0xed6c}, - [ISP_IMX614_2921_02] = {0x614, 0x29210202, "isp/2921_02XX.dat", 0xed6c}, - [ISP_IMX614_2922_02] = {0x614, 0x29220201, "isp/2922_02XX.dat", 0xed6c}, - [ISP_IMX633_3622_01] = {0x633, 0x36220111, "isp/3622_01XX.dat", 0x100d4}, - [ISP_IMX703_7721_01] = {0x703, 0x77210106, "isp/7721_01XX.dat", 0x936c}, - [ISP_IMX703_7722_01] = {0x703, 0x77220106, "isp/7722_01XX.dat", 0xac20}, - [ISP_IMX713_4721_01] = {0x713, 0x47210107, "isp/4721_01XX.dat", 0x936c}, - [ISP_IMX713_4722_01] = {0x713, 0x47220109, "isp/4722_01XX.dat", 0x9218}, - [ISP_IMX714_2022_01] = {0x714, 0x20220107, "isp/2022_01XX.dat", 0xa198}, - [ISP_IMX772_3721_01] = {0x772, 0x37210106, "isp/3721_01XX.dat", 0xfdf8}, - [ISP_IMX772_3721_11] = {0x772, 0x37211106, "isp/3721_11XX.dat", 0xfe14}, - [ISP_IMX772_3722_01] = {0x772, 0x37220104, "isp/3722_01XX.dat", 0xfca4}, - [ISP_IMX772_3723_01] = {0x772, 0x37230106, "isp/3723_01XX.dat", 0xfca4}, - [ISP_IMX814_2123_01] = {0x814, 0x21230101, "isp/2123_01XX.dat", 0xed54}, - [ISP_IMX853_7622_01] = {0x853, 0x76220112, "isp/7622_01XX.dat", 0x247f8}, - [ISP_IMX913_7523_01] = {0x913, 0x75230107, "isp/7523_01XX.dat", 0x247f8}, - [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "isp/6221_01XX.dat", 0x1b80}, - [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "isp/6222_01XX.dat", 0x1b80}, -}; - -// one day we will do this intelligently -static const struct isp_preset isp_presets[] = { - [ISP_IMX248_1820_01] = {0, 1280, 720, 8, 8, 1280, 720, 1296, 736}, // J293AP - [ISP_IMX558_1921_01] = {1, 1920, 1080, 0, 0, 1920, 1080, 1920, 1080}, // J316sAP, J415AP + [ISP_IMX248_1820_01] = {0x248, 0x18200103, "apple/isp_1820_01XX.dat", 0x442c}, + [ISP_IMX248_1822_02] = {0x248, 0x18220201, "apple/isp_1822_02XX.dat", 0x442c}, + [ISP_IMX343_5221_02] = {0x343, 0x52210211, "apple/isp_5221_02XX.dat", 0x4870}, + [ISP_IMX354_9251_02] = {0x354, 0x92510208, "apple/isp_9251_02XX.dat", 0xa5ec}, + [ISP_IMX356_4820_01] = {0x356, 0x48200107, "apple/isp_4820_01XX.dat", 0x9324}, + [ISP_IMX356_4820_02] = {0x356, 0x48200206, "apple/isp_4820_02XX.dat", 0x9324}, + [ISP_IMX364_8720_01] = {0x364, 0x87200103, "apple/isp_8720_01XX.dat", 0x36ac}, + [ISP_IMX364_8723_01] = {0x364, 0x87230101, "apple/isp_8723_01XX.dat", 0x361c}, + [ISP_IMX372_3820_01] = {0x372, 0x38200108, "apple/isp_3820_01XX.dat", 0xfdb0}, + [ISP_IMX372_3820_02] = {0x372, 0x38200205, "apple/isp_3820_02XX.dat", 0xfdb0}, + [ISP_IMX372_3820_11] = {0x372, 0x38201104, "apple/isp_3820_11XX.dat", 0xfdb0}, + [ISP_IMX372_3820_12] = {0x372, 0x38201204, "apple/isp_3820_12XX.dat", 0xfdb0}, + [ISP_IMX405_9720_01] = {0x405, 0x97200102, "apple/isp_9720_01XX.dat", 0x92c8}, + [ISP_IMX405_9721_01] = {0x405, 0x97210102, "apple/isp_9721_01XX.dat", 0x9818}, + [ISP_IMX405_9723_01] = {0x405, 0x97230101, "apple/isp_9723_01XX.dat", 0x92c8}, + [ISP_IMX414_2520_01] = {0x414, 0x25200102, "apple/isp_2520_01XX.dat", 0xa444}, + [ISP_IMX503_7820_01] = {0x503, 0x78200109, "apple/isp_7820_01XX.dat", 0xb268}, + [ISP_IMX503_7820_02] = {0x503, 0x78200206, "apple/isp_7820_02XX.dat", 0xb268}, + [ISP_IMX505_3921_01] = {0x505, 0x39210102, "apple/isp_3921_01XX.dat", 0x89b0}, + [ISP_IMX514_2820_01] = {0x514, 0x28200108, "apple/isp_2820_01XX.dat", 0xa198}, + [ISP_IMX514_2820_02] = {0x514, 0x28200205, "apple/isp_2820_02XX.dat", 0xa198}, + [ISP_IMX514_2820_03] = {0x514, 0x28200305, "apple/isp_2820_03XX.dat", 0xa198}, + [ISP_IMX514_2820_04] = {0x514, 0x28200405, "apple/isp_2820_04XX.dat", 0xa198}, + [ISP_IMX558_1921_01] = {0x558, 0x19210106, "apple/isp_1921_01XX.dat", 0xad40}, + [ISP_IMX558_1922_02] = {0x558, 0x19220201, "apple/isp_1922_02XX.dat", 0xad40}, + [ISP_IMX603_7920_01] = {0x603, 0x79200109, "apple/isp_7920_01XX.dat", 0xad2c}, + [ISP_IMX603_7920_02] = {0x603, 0x79200205, "apple/isp_7920_02XX.dat", 0xad2c}, + [ISP_IMX603_7921_01] = {0x603, 0x79210104, "apple/isp_7921_01XX.dat", 0xad90}, + [ISP_IMX613_4920_01] = {0x613, 0x49200108, "apple/isp_4920_01XX.dat", 0x9324}, + [ISP_IMX613_4920_02] = {0x613, 0x49200204, "apple/isp_4920_02XX.dat", 0x9324}, + [ISP_IMX614_2921_01] = {0x614, 0x29210107, "apple/isp_2921_01XX.dat", 0xed6c}, + [ISP_IMX614_2921_02] = {0x614, 0x29210202, "apple/isp_2921_02XX.dat", 0xed6c}, + [ISP_IMX614_2922_02] = {0x614, 0x29220201, "apple/isp_2922_02XX.dat", 0xed6c}, + [ISP_IMX633_3622_01] = {0x633, 0x36220111, "apple/isp_3622_01XX.dat", 0x100d4}, + [ISP_IMX703_7721_01] = {0x703, 0x77210106, "apple/isp_7721_01XX.dat", 0x936c}, + [ISP_IMX703_7722_01] = {0x703, 0x77220106, "apple/isp_7722_01XX.dat", 0xac20}, + [ISP_IMX713_4721_01] = {0x713, 0x47210107, "apple/isp_4721_01XX.dat", 0x936c}, + [ISP_IMX713_4722_01] = {0x713, 0x47220109, "apple/isp_4722_01XX.dat", 0x9218}, + [ISP_IMX714_2022_01] = {0x714, 0x20220107, "apple/isp_2022_01XX.dat", 0xa198}, + [ISP_IMX772_3721_01] = {0x772, 0x37210106, "apple/isp_3721_01XX.dat", 0xfdf8}, + [ISP_IMX772_3721_11] = {0x772, 0x37211106, "apple/isp_3721_11XX.dat", 0xfe14}, + [ISP_IMX772_3722_01] = {0x772, 0x37220104, "apple/isp_3722_01XX.dat", 0xfca4}, + [ISP_IMX772_3723_01] = {0x772, 0x37230106, "apple/isp_3723_01XX.dat", 0xfca4}, + [ISP_IMX814_2123_01] = {0x814, 0x21230101, "apple/isp_2123_01XX.dat", 0xed54}, + [ISP_IMX853_7622_01] = {0x853, 0x76220112, "apple/isp_7622_01XX.dat", 0x247f8}, + [ISP_IMX913_7523_01] = {0x913, 0x75230107, "apple/isp_7523_01XX.dat", 0x247f8}, + [ISP_VD56G0_6221_01] = {0xd56, 0x62210102, "apple/isp_6221_01XX.dat", 0x1b80}, + [ISP_VD56G0_6222_01] = {0xd56, 0x62220102, "apple/isp_6222_01XX.dat", 0x1b80}, }; // clang-format on @@ -182,125 +166,69 @@ static int isp_ch_get_sensor_id(struct apple_isp *isp, u32 ch) return err; } -static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) +static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) { - struct isp_format *fmt = isp_get_format(isp, ch); int err = 0; - struct cmd_ch_info *args; /* Too big to allocate on stack */ + struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ args = kzalloc(sizeof(*args), GFP_KERNEL); if (!args) return -ENOMEM; - err = isp_cmd_ch_info_get(isp, ch, args); + err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); if (err) goto exit; - dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, - args->module_sn, ch); - - fmt->version = args->version; - fmt->num_presets = args->num_presets; - - pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); - print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); + print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, args, sizeof(*args), false); - err = isp_ch_get_sensor_id(isp, ch); - if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { - dev_err(isp->dev, - "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", - ch); - return -ENODEV; - } - exit: kfree(args); return err; } -static int isp_ch_get_camera_preset(struct apple_isp *isp, u32 ch, u32 ps) +static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) { + struct isp_format *fmt = isp_get_format(isp, ch); int err = 0; - struct cmd_ch_camera_config *args; /* Too big to allocate on stack */ + struct cmd_ch_info *args; /* Too big to allocate on stack */ args = kzalloc(sizeof(*args), GFP_KERNEL); if (!args) return -ENOMEM; - err = isp_cmd_ch_camera_config_get(isp, ch, ps, args); + err = isp_cmd_ch_info_get(isp, ch, args); if (err) goto exit; - pr_info("apple-isp: ps: CISP_CMD_CH_CAMERA_CONFIG_GET: %d\n", ps); - print_hex_dump(KERN_INFO, "apple-isp: ps: ", DUMP_PREFIX_NONE, 32, 4, - args, sizeof(*args), false); + dev_info(isp->dev, "found sensor %x %s on ch %d\n", args->version, + args->module_sn, ch); -exit: - kfree(args); + fmt->version = args->version; - return err; -} + pr_info("apple-isp: ch: CISP_CMD_CH_INFO_GET: %d\n", ch); + print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, + args, sizeof(*args), false); -static void isp_ch_dump_camera_presets(struct apple_isp *isp, u32 ch) -{ - struct isp_format *fmt = isp_get_format(isp, ch); - for (u32 ps = 0; ps < fmt->num_presets; ps++) { - isp_ch_get_camera_preset(isp, ch, ps); + err = isp_ch_get_sensor_id(isp, ch); + if (err || + (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { + dev_err(isp->dev, + "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", + ch); + return -ENODEV; } -} - -static int isp_ch_cache_camera_preset(struct apple_isp *isp, u32 ch) -{ - struct isp_format *fmt = isp_get_format(isp, ch); - const struct isp_preset *preset = &isp_presets[fmt->id]; - size_t total_size; - - isp_ch_dump_camera_presets(isp, ch); - - fmt->preset = preset->index; - - fmt->width = preset->width; - fmt->height = preset->height; - - fmt->x1 = preset->x1; - fmt->y1 = preset->y1; - fmt->x2 = preset->x2; - fmt->y2 = preset->y2; - - /* I really fucking hope they all use NV12. */ - fmt->num_planes = 2; - fmt->plane_size[0] = fmt->width * fmt->height; - fmt->plane_size[1] = fmt->plane_size[0] / 2; - - total_size = 0; - for (int i = 0; i < fmt->num_planes; i++) - total_size += fmt->plane_size[i]; - fmt->total_size = total_size; - - return 0; -} - -static int isp_ch_cache_camera_info(struct apple_isp *isp, u32 ch) -{ - int err; - err = isp_ch_cache_sensor_info(isp, ch); - if (err) { - dev_err(isp->dev, "ch %d: failed to cache sensor info: %d\n", - ch, err); - return err; + for (u32 ps = 0; ps < args->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); } - err = isp_ch_cache_camera_preset(isp, ch); - if (err) { - dev_err(isp->dev, "ch %d: failed to cache camera preset: %d\n", - ch, err); - return err; - } +exit: + kfree(args); - return 0; + return err; } static int isp_detect_camera(struct apple_isp *isp) @@ -338,7 +266,13 @@ static int isp_detect_camera(struct apple_isp *isp) isp->num_channels = args.num_channels; isp->current_ch = 0; - return isp_ch_cache_camera_info(isp, isp->current_ch); /* I told you */ + err = isp_ch_cache_sensor_info(isp, isp->current_ch); + if (err) { + dev_err(isp->dev, "failed to cache sensor info\n"); + return err; + } + + return 0; } int apple_isp_detect_camera(struct apple_isp *isp) @@ -408,6 +342,12 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) err); } + if (isp->hw->gen >= ISP_GEN_T8112) { + err = isp_cmd_ch_lpdp_hs_receiver_tuning_set(isp, ch, 1, 15); + if (err) + return err; + } + err = isp_cmd_ch_sbs_enable(isp, ch, 1); if (err) return err; @@ -421,17 +361,21 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset); + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); if (err) return err; - err = isp_cmd_ch_crop_set(isp, ch, fmt->x1, fmt->y1, fmt->x2, fmt->y2); + err = isp_cmd_ch_crop_set(isp, ch, fmt->preset->crop_offset.x, + fmt->preset->crop_offset.y, + fmt->preset->crop_size.x, + fmt->preset->crop_size.y); if (err) return err; - err = isp_cmd_ch_output_config_set(isp, ch, fmt->width, fmt->height, - CISP_COLORSPACE_REC709, - CISP_OUTPUT_FORMAT_NV12); + err = isp_cmd_ch_output_config_set(isp, ch, fmt->preset->output_dim.x, + fmt->preset->output_dim.y, + fmt->strides, CISP_COLORSPACE_REC709, + CISP_OUTPUT_FORMAT_YUV_2PLANE); if (err) return err; @@ -443,7 +387,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_mbnr_enable(isp, ch, 0, 1, 1); + err = isp_cmd_ch_mbnr_enable(isp, ch, 0, ISP_MBNR_MODE_ENABLE, 1); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 79ffb2b1c33881..1e812400e52f7d 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -119,6 +119,17 @@ int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, return CISP_SEND_IN(isp, args); } +int isp_cmd_set_dsid_clr_req_base(struct apple_isp *isp, u64 dsid_clr_base, + u32 dsid_clr_range) +{ + struct cmd_set_dsid_clr_req_base args = { + .opcode = CISP_OPCODE(CISP_CMD_SET_DSID_CLR_REG_BASE), + .dsid_clr_base = dsid_clr_base, + .dsid_clr_range = dsid_clr_range, + }; + return CISP_SEND_IN(isp, args); +} + int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, u64 clock_base, u8 clock_bit, u8 clock_size, u64 bandwidth_scratch, u64 bandwidth_base, @@ -218,16 +229,26 @@ int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } -int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size) { - struct cmd_ch_set_file_load args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), - .chan = chan, - .addr = addr, - .size = size, - }; - return CISP_SEND_IN(isp, args); + if (isp->hw->gen >= ISP_GEN_T8112) { + struct cmd_ch_set_file_load64 args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); + } else { + struct cmd_ch_set_file_load args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), + .chan = chan, + .addr = addr, + .size = size, + }; + return CISP_SEND_IN(isp, args); + } } int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable) @@ -244,7 +265,8 @@ int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, u32 y2) { struct cmd_ch_crop_set args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_CROP_SET), + .opcode = CISP_OPCODE(isp->hw->scl1 ? CISP_CMD_CH_CROP_SCL1_SET + : CISP_CMD_CH_CROP_SET), .chan = chan, .x1 = x1, .y1 = y1, @@ -255,23 +277,22 @@ int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, } int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, - u32 height, u32 colorspace, u32 format) + u32 height, u32 strides[3], u32 colorspace, u32 format) { struct cmd_ch_output_config_set args = { - .opcode = CISP_OPCODE(CISP_CMD_CH_OUTPUT_CONFIG_SET), + .opcode = CISP_OPCODE(isp->hw->scl1 ? CISP_CMD_CH_OUTPUT_CONFIG_SCL1_SET + : CISP_CMD_CH_OUTPUT_CONFIG_SET), .chan = chan, .width = width, .height = height, .colorspace = colorspace, .format = format, - .unk_w0 = width, - .unk_w1 = width, - .unk_24 = 0, .padding_rows = 0, .unk_h0 = height, .compress = 0, .unk_w2 = width, }; + memcpy(args.strides, strides, sizeof(args.strides)); return CISP_SEND_IN(isp, args); } @@ -356,12 +377,14 @@ int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) .chan = chan, .type = type, .count = 16, - .meta_size0 = ISP_META_SIZE, - .meta_size1 = ISP_META_SIZE, + .meta_size0 = isp->hw->meta_size, + .meta_size1 = isp->hw->meta_size, + .unk0 = 0, + .unk1 = 0, + .unk2 = 0, .data_blocks = 1, .compress = 0, }; - memset(args.zero, 0, sizeof(u32) * 0x1f); return CISP_SEND_INOUT(isp, args); } @@ -542,3 +565,40 @@ int isp_cmd_ch_semantic_awb_enable(struct apple_isp *isp, u32 chan, u32 enable) }; return CISP_SEND_IN(isp, args); } + +int isp_cmd_ch_lpdp_hs_receiver_tuning_set(struct apple_isp *isp, u32 chan, u32 unk1, u32 unk2) +{ + struct cmd_ch_lpdp_hs_receiver_tuning_set args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_LPDP_HS_RECEIVER_TUNING_SET), + .chan = chan, + .unk1 = unk1, + .unk2 = unk2, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_property_write(struct apple_isp *isp, u32 chan, u32 prop, u32 val) +{ + struct cmd_ch_property_write args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PROPERTY_WRITE), + .chan = chan, + .prop = prop, + .val = val, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_ch_property_read(struct apple_isp *isp, u32 chan, u32 prop, u32 *val) +{ + struct cmd_ch_property_write args = { + .opcode = CISP_OPCODE(CISP_CMD_CH_PROPERTY_READ), + .chan = chan, + .prop = prop, + .val = 0xdeadbeef, + }; + int ret = CISP_SEND_OUT(isp, &args); + + *val = args.val; + + return ret; +} diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 1fc484fa687853..1586df89f1cdab 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -35,10 +35,14 @@ #define CISP_CMD_CH_BUFFER_POOL_CONFIG_SET 0x0117 #define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_GET 0x011a #define CISP_CMD_CH_CAMERA_PIX_FREQUENCY_GET 0x011f +#define CISP_CMD_CH_PROPERTY_WRITE 0x0122 +#define CISP_CMD_CH_PROPERTY_READ 0x0123 #define CISP_CMD_CH_LOCAL_RAW_BUFFER_ENABLE 0x0125 +#define CISP_CMD_CH_META_DATA_ENABLE 0x0126 #define CISP_CMD_CH_CAMERA_MIPI_FREQUENCY_TOTAL_GET 0x0133 #define CISP_CMD_CH_SBS_ENABLE 0x013b #define CISP_CMD_CH_LSC_POLYNOMIAL_COEFF_GET 0x0142 +#define CISP_CMD_CH_SET_META_DATA_REQUIRED 0x014f #define CISP_CMD_CH_BUFFER_POOL_RETURN 0x015b #define CISP_CMD_CH_CAMERA_AGILE_FREQ_ARRAY_CURRENT_GET 0x015e #define CISP_CMD_CH_AE_START 0x0200 @@ -52,25 +56,35 @@ #define CISP_CMD_CH_SENSOR_NVM_GET 0x0501 #define CISP_CMD_CH_SENSOR_PERMODULE_LSC_INFO_GET 0x0507 #define CISP_CMD_CH_SENSOR_PERMODULE_LSC_GRID_GET 0x0511 +#define CISP_CMD_CH_LPDP_HS_RECEIVER_TUNING_SET 0x051b #define CISP_CMD_CH_FOCUS_LIMITS_GET 0x0701 +#define CISP_CMD_CH_CROP_GET 0x0800 #define CISP_CMD_CH_CROP_SET 0x0801 +#define CISP_CMD_CH_SCALER_CROP_SET 0x080a +#define CISP_CMD_CH_CROP_SCL1_GET 0x080b +#define CISP_CMD_CH_CROP_SCL1_SET 0x080c +#define CISP_CMD_CH_SCALER_CROP_SCL1_SET 0x080d #define CISP_CMD_CH_ALS_ENABLE 0x0a1c #define CISP_CMD_CH_ALS_DISABLE 0x0a1d #define CISP_CMD_CH_CNR_START 0x0a2f #define CISP_CMD_CH_MBNR_ENABLE 0x0a3a #define CISP_CMD_CH_OUTPUT_CONFIG_SET 0x0b01 +#define CISP_CMD_CH_OUTPUT_CONFIG_SCL1_SET 0x0b09 #define CISP_CMD_CH_PREVIEW_STREAM_SET 0x0b0d #define CISP_CMD_CH_SEMANTIC_VIDEO_ENABLE 0x0b17 #define CISP_CMD_CH_SEMANTIC_AWB_ENABLE 0x0b18 #define CISP_CMD_CH_FACE_DETECTION_START 0x0d00 +#define CISP_CMD_CH_FACE_DETECTION_STOP 0x0d01 #define CISP_CMD_CH_FACE_DETECTION_CONFIG_GET 0x0d02 #define CISP_CMD_CH_FACE_DETECTION_CONFIG_SET 0x0d03 +#define CISP_CMD_CH_FACE_DETECTION_DISABLE 0x0d04 #define CISP_CMD_CH_FACE_DETECTION_ENABLE 0x0d05 #define CISP_CMD_CH_FID_START 0x3000 #define CISP_CMD_CH_FID_STOP 0x3001 #define CISP_CMD_IPC_ENDPOINT_SET2 0x300c #define CISP_CMD_IPC_ENDPOINT_UNSET2 0x300d #define CISP_CMD_SET_DSID_CLR_REG_BASE2 0x3204 +#define CISP_CMD_SET_DSID_CLR_REG_BASE 0x3205 #define CISP_CMD_APPLE_CH_AE_METERING_MODE_SET 0x8206 #define CISP_CMD_APPLE_CH_AE_FD_SCENE_METERING_CONFIG_SET 0x820e #define CISP_CMD_APPLE_CH_AE_FLICKER_FREQ_UPDATE_CURRENT_SET 0x8212 @@ -86,10 +100,28 @@ #define CISP_POOL_TYPE_FD 0x2 #define CISP_POOL_TYPE_RAW 0x3 #define CISP_POOL_TYPE_STAT 0x4 +#define CISP_POOL_TYPE_RAW_AUX 0x5 +#define CISP_POOL_TYPE_YCC 0x6 +#define CISP_POOL_TYPE_CAPTURE_FULL_RES 0x7 #define CISP_POOL_TYPE_META_CAPTURE 0x8 +#define CISP_POOL_TYPE_RENDERED_SCL1 0x9 +#define CISP_POOL_TYPE_STAT_PIXELOUTPUT 0x11 +#define CISP_POOL_TYPE_FSCL 0x12 +#define CISP_POOL_TYPE_CAPTURE_FULL_RES_YCC 0x13 +#define CISP_POOL_TYPE_RENDERED_RAW 0x14 +#define CISP_POOL_TYPE_CAPTURE_PDC_RAW 0x16 +#define CISP_POOL_TYPE_FPC_DATA 0x17 +#define CISP_POOL_TYPE_AICAM_SEG 0x19 +#define CISP_POOL_TYPE_SPD 0x1a +#define CISP_POOL_TYPE_META_DEPTH 0x1c +#define CISP_POOL_TYPE_JASPER_DEPTH 0x1d +#define CISP_POOL_TYPE_RAW_SIFR 0x1f +#define CISP_POOL_TYPE_FEP_THUMBNAIL_DYNAMIC_POOL_RAW 0x21 #define CISP_COLORSPACE_REC709 0x1 -#define CISP_OUTPUT_FORMAT_NV12 0x0 +#define CISP_OUTPUT_FORMAT_YUV_2PLANE 0x0 +#define CISP_OUTPUT_FORMAT_YUV_1PLANE 0x1 +#define CISP_OUTPUT_FORMAT_RGB 0x2 #define CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY 0x1 struct cmd_start { @@ -144,6 +176,13 @@ struct cmd_set_dsid_clr_req_base2 { } __packed; static_assert(sizeof(struct cmd_set_dsid_clr_req_base2) == 0x38); +struct cmd_set_dsid_clr_req_base { + u64 opcode; + u64 dsid_clr_base; + u32 dsid_clr_range; +} __packed; +static_assert(sizeof(struct cmd_set_dsid_clr_req_base) == 0x14); + struct cmd_pmp_ctrl_set { u64 opcode; u64 clock_scratch; @@ -169,12 +208,26 @@ struct cmd_fid_exit { } __packed; static_assert(sizeof(struct cmd_fid_exit) == 0x8); +struct cmd_ipc_endpoint_set2 { + u64 opcode; + u32 unk; + u64 addr1; + u32 size1; + u64 addr2; + u32 size2; + u64 regs; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); + int isp_cmd_start(struct apple_isp *isp, u32 mode); int isp_cmd_suspend(struct apple_isp *isp); int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); int isp_cmd_config_get(struct apple_isp *isp, struct cmd_config_get *args); int isp_cmd_set_isp_pmu_base(struct apple_isp *isp, u64 pmu_base); +int isp_cmd_set_dsid_clr_req_base(struct apple_isp *isp, u64 dsid_clr_base, + u32 dsid_clr_range); int isp_cmd_set_dsid_clr_req_base2(struct apple_isp *isp, u64 dsid_clr_base0, u64 dsid_clr_base1, u64 dsid_clr_base2, u64 dsid_clr_base3, u32 dsid_clr_range0, @@ -291,6 +344,14 @@ struct cmd_ch_set_file_load { } __packed; static_assert(sizeof(struct cmd_ch_set_file_load) == 0x14); +struct cmd_ch_set_file_load64 { + u64 opcode; + u32 chan; + u64 addr; + u32 size; +} __packed; +static_assert(sizeof(struct cmd_ch_set_file_load64) == 0x18); + struct cmd_ch_buffer_return { u64 opcode; u32 chan; @@ -321,9 +382,7 @@ struct cmd_ch_output_config_set { u32 height; u32 colorspace; u32 format; - u32 unk_w0; - u32 unk_w1; - u32 unk_24; + u32 strides[3]; u32 padding_rows; u32 unk_h0; u32 compress; @@ -369,6 +428,24 @@ struct cmd_ch_sif_pixel_format_set { } __packed; static_assert(sizeof(struct cmd_ch_sif_pixel_format_set) == 0x14); +struct cmd_ch_lpdp_hs_receiver_tuning_set { + u64 opcode; + u32 chan; + u32 unk1; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ch_lpdp_hs_receiver_tuning_set) == 0x14); + +struct cmd_ch_property_write { + u64 opcode; + u32 chan; + u32 prop; + u32 val; + u32 unk1; + u32 unk2; +} __packed; +static_assert(sizeof(struct cmd_ch_property_write) == 0x1c); + int isp_cmd_ch_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan); int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, @@ -379,20 +456,30 @@ int isp_cmd_ch_camera_config_current_get(struct apple_isp *isp, u32 chan, struct cmd_ch_camera_config *args); int isp_cmd_ch_camera_config_select(struct apple_isp *isp, u32 chan, u32 preset); -int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u32 addr, +int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size); int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan); int isp_cmd_ch_sbs_enable(struct apple_isp *isp, u32 chan, u32 enable); int isp_cmd_ch_crop_set(struct apple_isp *isp, u32 chan, u32 x1, u32 y1, u32 x2, u32 y2); int isp_cmd_ch_output_config_set(struct apple_isp *isp, u32 chan, u32 width, - u32 height, u32 colorspace, u32 format); + u32 height, u32 strides[3], u32 colorspace, u32 format); int isp_cmd_ch_preview_stream_set(struct apple_isp *isp, u32 chan, u32 stream); int isp_cmd_ch_als_disable(struct apple_isp *isp, u32 chan); int isp_cmd_ch_cnr_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_mbnr_enable(struct apple_isp *isp, u32 chan, u32 use_case, u32 mode, u32 enable_chroma); int isp_cmd_ch_sif_pixel_format_set(struct apple_isp *isp, u32 chan); +int isp_cmd_ch_lpdp_hs_receiver_tuning_set(struct apple_isp *isp, u32 chan, u32 unk1, u32 unk2); + +int isp_cmd_ch_property_read(struct apple_isp *isp, u32 chan, u32 prop, u32 *val); +int isp_cmd_ch_property_write(struct apple_isp *isp, u32 chan, u32 prop, u32 val); + +enum isp_mbnr_mode { + ISP_MBNR_MODE_DISABLE = 0, + ISP_MBNR_MODE_ENABLE = 1, + ISP_MBNR_MODE_BYPASS = 2, +}; struct cmd_ch_buffer_recycle_mode_set { u64 opcode; @@ -414,7 +501,10 @@ struct cmd_ch_buffer_pool_config_set { u16 count; u32 meta_size0; u32 meta_size1; - u32 zero[0x1f]; + u64 unk0; + u64 unk1; + u64 unk2; + u32 zero[0x19]; u32 data_blocks; u32 compress; } __packed; @@ -431,6 +521,8 @@ int isp_cmd_ch_buffer_recycle_mode_set(struct apple_isp *isp, u32 chan, int isp_cmd_ch_buffer_recycle_start(struct apple_isp *isp, u32 chan); int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type); +int isp_cmd_ch_buffer_pool_config_get(struct apple_isp *isp, u32 chan, + u16 type); int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan); struct cmd_apple_ch_temporal_filter_start { diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index cad201a62b8434..a887e342115311 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -90,7 +90,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) return -ENODEV; isp->shift = __ffs(isp->domain->pgsize_bitmap); - idx = of_property_match_string(dev->of_node, "memory-region-names", "heap"); + idx = of_property_match_string(dev->of_node, "memory-region-names", + "heap"); mem_node = of_parse_phandle(dev->of_node, "memory-region", idx); if (!mem_node) { dev_err(dev, "No memory-region found for heap\n"); @@ -107,11 +108,10 @@ static int apple_isp_init_iommu(struct apple_isp *isp) while (maps < end) { maps++; - maps = of_translate_dma_region(dev->of_node, maps, &heap_base, &heap_size); + maps = of_translate_dma_region(dev->of_node, maps, &heap_base, + &heap_size); } - printk("heap: 0x%llx 0x%lx\n", heap_base, heap_size); - isp->fw.heap_top = heap_base + heap_size; err = of_property_read_u64(dev->of_node, "apple,dart-vm-size", @@ -122,7 +122,8 @@ static int apple_isp_init_iommu(struct apple_isp *isp) } // FIXME: refactor this, maybe use regular iova stuff? - drm_mm_init(&isp->iovad, isp->fw.heap_top, vm_size - (heap_base & 0xffffffff)); + drm_mm_init(&isp->iovad, isp->fw.heap_top, + vm_size - (heap_base & 0xffffffff)); return 0; } @@ -132,6 +133,92 @@ static void apple_isp_free_iommu(struct apple_isp *isp) drm_mm_takedown(&isp->iovad); } +/* NOTE: of_node_put()s the OF node on failure. */ +static int isp_of_read_coord(struct device *dev, struct device_node *np, + const char *prop, struct coord *val) +{ + u32 xy[2]; + int ret; + + ret = of_property_read_u32_array(np, prop, xy, 2); + if (ret) { + dev_err(dev, "failed to read '%s' property\n", prop); + of_node_put(np); + return ret; + } + + val->x = xy[0]; + val->y = xy[1]; + return 0; +} + +static int apple_isp_init_presets(struct apple_isp *isp) +{ + struct device *dev = isp->dev; + struct device_node *np, *child; + struct isp_preset *preset; + int err = 0; + + np = of_get_child_by_name(dev->of_node, "sensor-presets"); + if (!np) { + dev_err(dev, "failed to get DT node 'presets'\n"); + return -EINVAL; + } + + isp->num_presets = of_get_child_count(np); + if (!isp->num_presets) { + dev_err(dev, "no sensor presets found\n"); + err = -EINVAL; + goto err; + } + + isp->presets = devm_kzalloc( + dev, sizeof(*isp->presets) * isp->num_presets, GFP_KERNEL); + if (!isp->presets) { + err = -ENOMEM; + goto err; + } + + preset = isp->presets; + for_each_child_of_node(np, child) { + u32 xywh[4]; + + err = of_property_read_u32(child, "apple,config-index", + &preset->index); + if (err) { + dev_err(dev, "no apple,config-index property\n"); + of_node_put(child); + goto err; + } + + err = isp_of_read_coord(dev, child, "apple,input-size", + &preset->input_dim); + if (err) + goto err; + err = isp_of_read_coord(dev, child, "apple,output-size", + &preset->output_dim); + if (err) + goto err; + + err = of_property_read_u32_array(child, "apple,crop", xywh, 4); + if (err) { + dev_err(dev, "failed to read 'apple,crop' property\n"); + of_node_put(child); + goto err; + } + preset->crop_offset.x = xywh[0]; + preset->crop_offset.y = xywh[1]; + preset->crop_size.x = xywh[2]; + preset->crop_size.y = xywh[3]; + + preset++; + } + +err: + of_node_put(np); + return err; +} + static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -151,6 +238,20 @@ static int apple_isp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isp); dev_set_drvdata(dev, isp); + err = of_property_read_u32(dev->of_node, "apple,platform-id", + &isp->platform_id); + if (err) { + dev_err(dev, "failed to get 'apple,platform-id' property: %d\n", + err); + return err; + } + + err = apple_isp_init_presets(isp); + if (err) { + dev_err(dev, "failed to initialize presets\n"); + return err; + } + err = apple_isp_attach_genpd(isp); if (err) { dev_err(dev, "failed to attatch power domains\n"); @@ -190,7 +291,8 @@ static int apple_isp_probe(struct platform_device *pdev) spin_lock_init(&isp->buf_lock); init_waitqueue_head(&isp->wait); INIT_LIST_HEAD(&isp->gc); - INIT_LIST_HEAD(&isp->buffers); + INIT_LIST_HEAD(&isp->bufs_pending); + INIT_LIST_HEAD(&isp->bufs_submitted); isp->wq = alloc_workqueue("apple-isp-wq", WQ_UNBOUND, 0); if (!isp->wq) { dev_err(dev, "failed to create workqueue\n"); @@ -254,9 +356,10 @@ static int apple_isp_remove(struct platform_device *pdev) } static const struct apple_isp_hw apple_isp_hw_t8103 = { - .platform_id = 0x1, + .gen = ISP_GEN_T8103, .pmu_base = 0x23b704000, + .dsid_count = 4, .dsid_clr_base0 = 0x200014000, .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -274,12 +377,16 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_base = 0x23bc3c000, .bandwidth_bit = 0x0, .bandwidth_size = 0x4, + + .scl1 = false, + .meta_size = ISP_META_SIZE_T8103, }; static const struct apple_isp_hw apple_isp_hw_t6000 = { - .platform_id = 0x3, + .gen = ISP_GEN_T8103, .pmu_base = 0x28e584000, + .dsid_count = 1, .dsid_clr_base0 = 0x200014000, .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -297,12 +404,16 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = false, + .meta_size = ISP_META_SIZE_T8103, }; static const struct apple_isp_hw apple_isp_hw_t8110 = { - .platform_id = 0xe, // J413AP + .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, + .dsid_count = 4, .dsid_clr_base0 = 0x200014000, // TODO .dsid_clr_base1 = 0x200054000, .dsid_clr_base2 = 0x200094000, @@ -320,29 +431,30 @@ static const struct apple_isp_hw apple_isp_hw_t8110 = { .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = true, + .meta_size = ISP_META_SIZE_T8112, }; static const struct apple_isp_hw apple_isp_hw_t6020 = { - .platform_id = 0x7, // J416cAP + .gen = ISP_GEN_T8112, .pmu_base = 0x290284000, - .dsid_clr_base0 = 0x200014000, // TODO - .dsid_clr_base1 = 0x200054000, - .dsid_clr_base2 = 0x200094000, - .dsid_clr_base3 = 0x2000d4000, + .dsid_count = 1, + .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, - .dsid_clr_range1 = 0x1000, - .dsid_clr_range2 = 0x1000, - .dsid_clr_range3 = 0x1000, - .clock_scratch = 0x28e3d0868, // CHECK + .clock_scratch = 0x28e3d10a8, .clock_base = 0x0, .clock_bit = 0x0, .clock_size = 0x8, - .bandwidth_scratch = 0x28e3d0980, // CHECK + .bandwidth_scratch = 0x28e3d1200, .bandwidth_base = 0x0, .bandwidth_bit = 0x0, .bandwidth_size = 0x8, + + .scl1 = true, + .meta_size = ISP_META_SIZE_T8112, }; static const struct of_device_id apple_isp_of_match[] = { @@ -362,7 +474,8 @@ static __maybe_unused int apple_isp_resume(struct device *dev) { return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, NULL); +DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, + NULL); static struct platform_driver apple_isp_driver = { .driver = { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index e672c62c0ec41c..926c921849544a 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -20,7 +20,13 @@ #define ISP_MAX_CHANNELS 6 #define ISP_IPC_MESSAGE_SIZE 64 #define ISP_IPC_FLAG_ACK 0x1 -#define ISP_META_SIZE 0x4640 +#define ISP_META_SIZE_T8103 0x4640 +#define ISP_META_SIZE_T8112 0x4840 + +enum isp_generation { + ISP_GEN_T8103, + ISP_GEN_T8112, +}; struct isp_surf { struct drm_mm_node *mm; @@ -62,10 +68,24 @@ struct isp_channel { const struct isp_chan_ops *ops; }; +struct coord { + u32 x; + u32 y; +}; + +struct isp_preset { + u32 index; + struct coord input_dim; + struct coord output_dim; + struct coord crop_offset; + struct coord crop_size; +}; + struct apple_isp_hw { - u32 platform_id; + enum isp_generation gen; u64 pmu_base; + int dsid_count; u64 dsid_clr_base0; u64 dsid_clr_base1; u64 dsid_clr_base2; @@ -83,6 +103,9 @@ struct apple_isp_hw { u64 bandwidth_base; u8 bandwidth_bit; u8 bandwidth_size; + + u32 meta_size; + bool scl1; }; enum isp_sensor_id { @@ -139,15 +162,9 @@ enum isp_sensor_id { struct isp_format { enum isp_sensor_id id; u32 version; - u32 num_presets; - u32 preset; - u32 width; - u32 height; - u32 x1; - u32 y1; - u32 x2; - u32 y2; + struct isp_preset *preset; unsigned int num_planes; + u32 strides[VB2_MAX_PLANES]; size_t plane_size[VB2_MAX_PLANES]; size_t total_size; }; @@ -155,6 +172,9 @@ struct isp_format { struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; + u32 platform_id; + struct isp_preset *presets; + int num_presets; int num_channels; struct isp_format fmts[ISP_MAX_CHANNELS]; @@ -208,7 +228,8 @@ struct apple_isp { unsigned long state; spinlock_t buf_lock; - struct list_head buffers; + struct list_head bufs_pending; + struct list_head bufs_submitted; }; struct isp_chan_ops { diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index bf06f6b3d4017d..cfb1aca37ebebe 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -45,7 +45,10 @@ struct isp_firmware_bootargs { u64 extra_iova; u64 extra_size; u32 platform_id; - u32 pad_40[7]; + u32 pad_40; + u64 logbuf_addr; + u64 logbuf_size; + u64 logbuf_entsize; u32 ipc_size; u32 pad_60[5]; u32 unk5; @@ -278,9 +281,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.shared_size = 0x10000000UL - args.shared_base; args.extra_iova = isp->extra_surf->iova; args.extra_size = isp->extra_surf->size; - args.platform_id = isp->hw->platform_id; + args.platform_id = isp->platform_id; args.unk5 = 0x40; - args.unk7 = 0x1; + args.unk7 = 0x1; // 0? args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; isp_iowrite(isp, args_iova, &args, sizeof(args)); @@ -500,13 +503,20 @@ static int isp_start_command_processor(struct apple_isp *isp) if (err) return err; - err = isp_cmd_set_dsid_clr_req_base2( - isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, - isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, - isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, - isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); - if (err) - return err; + if (isp->hw->dsid_count == 1) { + err = isp_cmd_set_dsid_clr_req_base( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_range0); + if (err) + return err; + } else { + err = isp_cmd_set_dsid_clr_req_base2( + isp, isp->hw->dsid_clr_base0, isp->hw->dsid_clr_base1, + isp->hw->dsid_clr_base2, isp->hw->dsid_clr_base3, + isp->hw->dsid_clr_range0, isp->hw->dsid_clr_range1, + isp->hw->dsid_clr_range2, isp->hw->dsid_clr_range3); + if (err) + return err; + } err = isp_cmd_pmp_ctrl_set( isp, isp->hw->clock_scratch, isp->hw->clock_base, diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index a9a0fdb73a4d9f..14249a44798ba5 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -230,8 +230,8 @@ static void sm_malloc_deferred_worker(struct work_struct *work) } #ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. */ if (!test_bit(ISP_STATE_LOGGING, &isp->state)) set_bit(ISP_STATE_LOGGING, &isp->state); @@ -306,9 +306,10 @@ int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) sizeof(meta_iova)); spin_lock(&isp->buf_lock); - list_for_each_entry_safe_reverse(buf, tmp, &isp->buffers, link) { - if (buf->meta->iova == meta_iova) { + list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { + if ((u32)buf->meta->iova == (u32)meta_iova) { enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; + buf->vb.vb2_buf.timestamp = ktime_get_ns(); buf->vb.sequence = isp->sequence++; buf->vb.field = V4L2_FIELD_NONE; diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index abdda01bfa2cec..49e6557fe86a94 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -13,10 +13,11 @@ #include "isp-ipc.h" #include "isp-v4l2.h" -#define ISP_MIN_FRAMES 2 -#define ISP_MAX_PLANES 4 -#define ISP_MAX_PIX_FORMATS 2 -#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) +#define ISP_MIN_FRAMES 2 +#define ISP_MAX_PLANES 4 +#define ISP_MAX_PIX_FORMATS 2 +#define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) +#define ISP_STRIDE_ALIGNMENT 64 struct isp_h2t_buffer { u64 iovas[ISP_MAX_PLANES]; @@ -40,7 +41,7 @@ static int isp_submit_buffers(struct apple_isp *isp) struct isp_format *fmt = isp_get_current_format(isp); struct isp_channel *chan = isp->chan_bh; struct isp_message *req = &chan->req; - struct isp_buffer *buf; + struct isp_buffer *buf, *buf2, *tmp; unsigned long flags; size_t offset; int err; @@ -51,43 +52,76 @@ static int isp_submit_buffers(struct apple_isp *isp) return -ENOMEM; spin_lock_irqsave(&isp->buf_lock, flags); - buf = list_first_entry_or_null(&isp->buffers, struct isp_buffer, link); - if (!buf) { + while ((buf = list_first_entry_or_null(&isp->bufs_pending, + struct isp_buffer, link))) { + args->meta.num_planes = 1; + args->meta.pool_type = 0; + args->meta.iovas[0] = buf->meta->iova; + args->meta.flags[0] = 0x40000000; + + args->render.num_planes = fmt->num_planes; + args->render.pool_type = isp->hw->scl1 ? + CISP_POOL_TYPE_RENDERED_SCL1 : + CISP_POOL_TYPE_RENDERED; + offset = 0; + for (int j = 0; j < fmt->num_planes; j++) { + args->render.iovas[j] = buf->surfs[0].iova + offset; + args->render.flags[j] = 0x40000000; + offset += fmt->plane_size[j]; + } + + /* + * Queue the buffer as submitted and release the lock for now. + * We need to do this before actually submitting to avoid a + * race with the buffer return codepath. + */ + list_move_tail(&buf->link, &isp->bufs_submitted); spin_unlock_irqrestore(&isp->buf_lock, flags); - kfree(args); - return -EPROTO; - } - args->meta.num_planes = 1; - args->meta.pool_type = CISP_POOL_TYPE_META; - args->meta.iovas[0] = buf->meta->iova; - args->meta.flags[0] = 0x40000000; - - args->render.num_planes = fmt->num_planes; - args->render.pool_type = CISP_POOL_TYPE_RENDERED; - offset = 0; - for (int j = 0; j < fmt->num_planes; j++) { - args->render.iovas[j] = buf->surfs[0].iova + offset; - args->render.flags[j] = 0x40000000; - offset += fmt->plane_size[j]; + args->enable = 0x1; + args->num_buffers = 2; + + req->arg0 = isp->cmd_iova; + req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + isp_iowrite(isp, req->arg0, args, sizeof(*args)); + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + /* If we fail, consider the buffer not submitted. */ + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + + /* + * Try to find the buffer in the list, and if it's + * still there, move it back to the pending list. + */ + spin_lock_irqsave(&isp->buf_lock, flags); + list_for_each_entry_safe_reverse( + buf2, tmp, &isp->bufs_submitted, link) { + if (buf2 == buf) { + list_move_tail(&buf->link, + &isp->bufs_pending); + spin_unlock_irqrestore(&isp->buf_lock, + flags); + return err; + } + } + /* + * We didn't find the buffer, which means it somehow was returned + * by the firmware even though submission failed? + */ + dev_err(isp->dev, + "buffer submission failed but buffer was returned?\n"); + spin_unlock_irqrestore(&isp->buf_lock, flags); + return err; + } + + spin_lock_irqsave(&isp->buf_lock, flags); } spin_unlock_irqrestore(&isp->buf_lock, flags); - args->enable = 0x1; - args->num_buffers = 2; - - req->arg0 = isp->cmd_iova; - req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; - req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - - isp_iowrite(isp, req->arg0, args, sizeof(*args)); - err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); - if (err) { - dev_err(isp->dev, - "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", - chan->name, req->arg0, req->arg1, req->arg2); - } - kfree(args); return err; @@ -140,7 +174,7 @@ static int isp_vb2_buf_init(struct vb2_buffer *vb) unsigned int i; int err; - buf->meta = isp_alloc_surface(isp, ISP_META_SIZE); + buf->meta = isp_alloc_surface(isp, isp->hw->meta_size); if (!buf->meta) return -ENOMEM; @@ -179,9 +213,12 @@ static void isp_vb2_release_buffers(struct apple_isp *isp, unsigned long flags; spin_lock_irqsave(&isp->buf_lock, flags); - list_for_each_entry(buf, &isp->buffers, link) + list_for_each_entry(buf, &isp->bufs_submitted, link) + vb2_buffer_done(&buf->vb.vb2_buf, state); + INIT_LIST_HEAD(&isp->bufs_submitted); + list_for_each_entry(buf, &isp->bufs_pending, link) vb2_buffer_done(&buf->vb.vb2_buf, state); - INIT_LIST_HEAD(&isp->buffers); + INIT_LIST_HEAD(&isp->bufs_pending); spin_unlock_irqrestore(&isp->buf_lock, flags); } @@ -194,8 +231,9 @@ static void isp_vb2_buf_queue(struct vb2_buffer *vb) bool empty; spin_lock_irqsave(&isp->buf_lock, flags); - empty = list_empty(&isp->buffers); - list_add_tail(&buf->link, &isp->buffers); + empty = list_empty(&isp->bufs_pending) && + list_empty(&isp->bufs_submitted); + list_add_tail(&buf->link, &isp->bufs_pending); spin_unlock_irqrestore(&isp->buf_lock, flags); if (test_bit(ISP_STATE_STREAMING, &isp->state) && !empty) @@ -249,17 +287,64 @@ static void isp_vb2_stop_streaming(struct vb2_queue *q) } static const struct vb2_ops isp_vb2_ops = { - .queue_setup = isp_vb2_queue_setup, - .buf_init = isp_vb2_buf_init, - .buf_cleanup = isp_vb2_buf_cleanup, - .buf_prepare = isp_vb2_buf_prepare, - .buf_queue = isp_vb2_buf_queue, + .queue_setup = isp_vb2_queue_setup, + .buf_init = isp_vb2_buf_init, + .buf_cleanup = isp_vb2_buf_cleanup, + .buf_prepare = isp_vb2_buf_prepare, + .buf_queue = isp_vb2_buf_queue, .start_streaming = isp_vb2_start_streaming, - .stop_streaming = isp_vb2_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, + .stop_streaming = isp_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; +static int isp_set_preset(struct apple_isp *isp, struct isp_format *fmt, + struct isp_preset *preset) +{ + int i; + size_t total_size; + + fmt->preset = preset; + + /* I really fucking hope they all use NV12. */ + fmt->num_planes = 2; + fmt->strides[0] = ALIGN(preset->output_dim.x, ISP_STRIDE_ALIGNMENT); + /* UV subsampled interleaved */ + fmt->strides[1] = ALIGN(preset->output_dim.x, ISP_STRIDE_ALIGNMENT); + fmt->plane_size[0] = fmt->strides[0] * preset->output_dim.y; + fmt->plane_size[1] = fmt->strides[1] * preset->output_dim.y / 2; + + total_size = 0; + for (i = 0; i < fmt->num_planes; i++) + total_size += fmt->plane_size[i]; + fmt->total_size = total_size; + + return 0; +} + +struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, + u32 height) +{ + struct isp_preset *preset, *best = &isp->presets[0]; + int i, score, best_score = INT_MAX; + + /* Default if no dimensions */ + if (width == 0 || height == 0) + return &isp->presets[0]; + + for (i = 0; i < isp->num_presets; i++) { + preset = &isp->presets[i]; + score = abs((int)preset->output_dim.x - (int)width) + + abs((int)preset->output_dim.y - (int)height); + if (score < best_score) { + best = preset; + best_score = score; + } + } + + return best; +} + /* * V4L2 ioctl section */ @@ -290,29 +375,28 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *f) { struct apple_isp *isp = video_drvdata(file); - struct isp_format *fmt = isp_get_current_format(isp); - if (f->index >= ISP_MAX_PIX_FORMATS) + if (f->index >= isp->num_presets) return -EINVAL; - if ((!f->index && f->pixel_format != V4L2_PIX_FMT_NV12) || - (f->index && f->pixel_format != V4L2_PIX_FMT_NV12M)) + if ((f->pixel_format != V4L2_PIX_FMT_NV12) || + (f->pixel_format != V4L2_PIX_FMT_NV12M)) return -EINVAL; - f->discrete.width = fmt->width; - f->discrete.height = fmt->height; + f->discrete.width = isp->presets[f->index].output_dim.x; + f->discrete.height = isp->presets[f->index].output_dim.y; f->type = V4L2_FRMSIZE_TYPE_DISCRETE; return 0; } -static inline void isp_set_sp_pix_format(struct apple_isp *isp, - struct v4l2_format *f) +static inline void isp_get_sp_pix_format(struct apple_isp *isp, + struct v4l2_format *f, + struct isp_format *fmt) { - struct isp_format *fmt = isp_get_current_format(isp); - - f->fmt.pix.width = fmt->width; - f->fmt.pix.height = fmt->height; + f->fmt.pix.width = fmt->preset->output_dim.x; + f->fmt.pix.height = fmt->preset->output_dim.y; + f->fmt.pix.bytesperline = fmt->strides[0]; f->fmt.pix.sizeimage = fmt->total_size; f->fmt.pix.field = V4L2_FIELD_NONE; @@ -322,16 +406,17 @@ static inline void isp_set_sp_pix_format(struct apple_isp *isp, f->fmt.pix.xfer_func = V4L2_XFER_FUNC_709; } -static inline void isp_set_mp_pix_format(struct apple_isp *isp, - struct v4l2_format *f) +static inline void isp_get_mp_pix_format(struct apple_isp *isp, + struct v4l2_format *f, + struct isp_format *fmt) { - struct isp_format *fmt = isp_get_current_format(isp); - - f->fmt.pix_mp.width = fmt->width; - f->fmt.pix_mp.height = fmt->height; + f->fmt.pix_mp.width = fmt->preset->output_dim.x; + f->fmt.pix_mp.height = fmt->preset->output_dim.y; f->fmt.pix_mp.num_planes = fmt->num_planes; - for (int i = 0; i < fmt->num_planes; i++) + for (int i = 0; i < fmt->num_planes; i++) { f->fmt.pix_mp.plane_fmt[i].sizeimage = fmt->plane_size[i]; + f->fmt.pix_mp.plane_fmt[i].bytesperline = fmt->strides[i]; + } f->fmt.pix_mp.field = V4L2_FIELD_NONE; f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; @@ -344,11 +429,12 @@ static int isp_vidioc_get_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); + isp_get_sp_pix_format(isp, f, fmt); return 0; } @@ -357,11 +443,19 @@ static int isp_vidioc_set_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); // no + preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); + err = isp_set_preset(isp, fmt, preset); + if (err) + return err; + + isp_get_sp_pix_format(isp, f, fmt); return 0; } @@ -370,11 +464,19 @@ static int isp_vidioc_try_format(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format fmt = *isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (isp->multiplanar) return -ENOTTY; - isp_set_sp_pix_format(isp, f); // still no + preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); + err = isp_set_preset(isp, &fmt, preset); + if (err) + return err; + + isp_get_sp_pix_format(isp, f, &fmt); return 0; } @@ -383,11 +485,12 @@ static int isp_vidioc_get_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); + isp_get_mp_pix_format(isp, f, fmt); return 0; } @@ -396,11 +499,20 @@ static int isp_vidioc_set_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format *fmt = isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); // no + preset = isp_select_preset(isp, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + err = isp_set_preset(isp, fmt, preset); + if (err) + return err; + + isp_get_mp_pix_format(isp, f, fmt); return 0; } @@ -409,11 +521,20 @@ static int isp_vidioc_try_format_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct apple_isp *isp = video_drvdata(file); + struct isp_format fmt = *isp_get_current_format(isp); + struct isp_preset *preset; + int err; if (!isp->multiplanar) return -ENOTTY; - isp_set_mp_pix_format(isp, f); // still no + preset = isp_select_preset(isp, f->fmt.pix_mp.width, + f->fmt.pix_mp.height); + err = isp_set_preset(isp, &fmt, preset); + if (err) + return err; + + isp_get_mp_pix_format(isp, f, &fmt); return 0; } @@ -472,6 +593,8 @@ static int isp_vidioc_set_param(struct file *file, void *fh, return -EINVAL; /* Not supporting frame rate sets. No use. Plus floats. */ + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.readbuffers = ISP_MIN_FRAMES; a->parm.capture.timeperframe.numerator = ISP_FRAME_RATE_NUM; a->parm.capture.timeperframe.denominator = ISP_FRAME_RATE_DEN; @@ -479,59 +602,67 @@ static int isp_vidioc_set_param(struct file *file, void *fh, } static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { - .vidioc_querycap = isp_vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, - .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, - .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, - .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, - .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, - .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, - .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, - - .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, - .vidioc_enum_input = isp_vidioc_enum_input, - .vidioc_g_input = isp_vidioc_get_input, - .vidioc_s_input = isp_vidioc_set_input, - .vidioc_g_parm = isp_vidioc_get_param, - .vidioc_s_parm = isp_vidioc_set_param, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_querycap = isp_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = isp_vidioc_enum_format, + .vidioc_g_fmt_vid_cap = isp_vidioc_get_format, + .vidioc_s_fmt_vid_cap = isp_vidioc_set_format, + .vidioc_try_fmt_vid_cap = isp_vidioc_try_format, + .vidioc_g_fmt_vid_cap_mplane = isp_vidioc_get_format_mplane, + .vidioc_s_fmt_vid_cap_mplane = isp_vidioc_set_format_mplane, + .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, + + .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_input = isp_vidioc_enum_input, + .vidioc_g_input = isp_vidioc_get_input, + .vidioc_s_input = isp_vidioc_set_input, + .vidioc_g_parm = isp_vidioc_get_param, + .vidioc_s_parm = isp_vidioc_set_param, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, }; static const struct v4l2_file_operations isp_v4l2_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, .unlocked_ioctl = video_ioctl2, }; static const struct media_device_ops isp_media_device_ops = { - .link_notify = v4l2_pipeline_link_notify, + .link_notify = v4l2_pipeline_link_notify, }; int apple_isp_setup_video(struct apple_isp *isp) { struct video_device *vdev = &isp->vdev; struct vb2_queue *vbq = &isp->vbq; + struct isp_format *fmt = isp_get_current_format(isp); int err; + err = isp_set_preset(isp, fmt, &isp->presets[0]); + if (err) { + dev_err(isp->dev, "failed to set default preset: %d\n", err); + return err; + } + media_device_init(&isp->mdev); isp->v4l2_dev.mdev = &isp->mdev; isp->mdev.ops = &isp_media_device_ops; isp->mdev.dev = isp->dev; - strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, sizeof(isp->mdev.model)); + strscpy(isp->mdev.model, APPLE_ISP_DEVICE_NAME, + sizeof(isp->mdev.model)); err = media_device_register(&isp->mdev); if (err) { From b77fd42a0f84ee6c0433eaa18c89b7e59efbb619 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 16:06:31 +0900 Subject: [PATCH 23/60] media: apple: isp: Always enable singleplane API, make multiple a module param This requires modifying the vbq type when set_format is called, depending on the style... this is ugly, but it should work? Multiplane is still quite broken, but this enables testing it with gstreamer. Still lots of things to fix to make this actually work. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-v4l2.c | 49 ++++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 49e6557fe86a94..c133544752e66a 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright 2023 Eileen Yoon */ +#include + #include #include #include @@ -19,6 +21,10 @@ #define ISP_BUFFER_TIMEOUT msecs_to_jiffies(1500) #define ISP_STRIDE_ALIGNMENT 64 +static bool multiplanar = false; +module_param(multiplanar, bool, 0644); +MODULE_PARM_DESC(multiplanar, "Enable multiplanar API"); + struct isp_h2t_buffer { u64 iovas[ISP_MAX_PLANES]; u32 flags[ISP_MAX_PLANES]; @@ -360,13 +366,23 @@ static int isp_vidioc_querycap(struct file *file, void *priv, static int isp_vidioc_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f) { + struct apple_isp *isp = video_drvdata(file); + if (f->index >= ISP_MAX_PIX_FORMATS) return -EINVAL; - if (!f->index) + switch (f->index) { + case 0: f->pixelformat = V4L2_PIX_FMT_NV12; - else + break; + case 1: + if (!isp->multiplanar) + return -EINVAL; f->pixelformat = V4L2_PIX_FMT_NV12M; + break; + default: + return -EINVAL; + } return 0; } @@ -379,7 +395,7 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, if (f->index >= isp->num_presets) return -EINVAL; - if ((f->pixel_format != V4L2_PIX_FMT_NV12) || + if ((f->pixel_format != V4L2_PIX_FMT_NV12) && (f->pixel_format != V4L2_PIX_FMT_NV12M)) return -EINVAL; @@ -431,9 +447,6 @@ static int isp_vidioc_get_format(struct file *file, void *fh, struct apple_isp *isp = video_drvdata(file); struct isp_format *fmt = isp_get_current_format(isp); - if (isp->multiplanar) - return -ENOTTY; - isp_get_sp_pix_format(isp, f, fmt); return 0; @@ -447,9 +460,6 @@ static int isp_vidioc_set_format(struct file *file, void *fh, struct isp_preset *preset; int err; - if (isp->multiplanar) - return -ENOTTY; - preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); err = isp_set_preset(isp, fmt, preset); if (err) @@ -457,6 +467,8 @@ static int isp_vidioc_set_format(struct file *file, void *fh, isp_get_sp_pix_format(isp, f, fmt); + isp->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + return 0; } @@ -468,9 +480,6 @@ static int isp_vidioc_try_format(struct file *file, void *fh, struct isp_preset *preset; int err; - if (isp->multiplanar) - return -ENOTTY; - preset = isp_select_preset(isp, f->fmt.pix.width, f->fmt.pix.height); err = isp_set_preset(isp, &fmt, preset); if (err) @@ -514,6 +523,8 @@ static int isp_vidioc_set_format_mplane(struct file *file, void *fh, isp_get_mp_pix_format(isp, f, fmt); + isp->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + return 0; } @@ -571,8 +582,9 @@ static int isp_vidioc_get_param(struct file *file, void *fh, { struct apple_isp *isp = video_drvdata(file); - if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + (!isp->multiplanar || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) return -EINVAL; a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; @@ -588,8 +600,9 @@ static int isp_vidioc_set_param(struct file *file, void *fh, { struct apple_isp *isp = video_drvdata(file); - if (a->type != (isp->multiplanar ? V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && + (!isp->multiplanar || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) return -EINVAL; /* Not supporting frame rate sets. No use. Plus floats. */ @@ -670,7 +683,7 @@ int apple_isp_setup_video(struct apple_isp *isp) goto media_cleanup; } - isp->multiplanar = 0; + isp->multiplanar = multiplanar; err = v4l2_device_register(isp->dev, &isp->v4l2_dev); if (err) { @@ -699,6 +712,8 @@ int apple_isp_setup_video(struct apple_isp *isp) vdev->fops = &isp_v4l2_fops; vdev->ioctl_ops = &isp_v4l2_ioctl_ops; vdev->device_caps = V4L2_BUF_TYPE_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + if (isp->multiplanar) + vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE_MPLANE; vdev->v4l2_dev = &isp->v4l2_dev; vdev->vfl_type = VFL_TYPE_VIDEO; vdev->vfl_dir = VFL_DIR_RX; From f9a760db990f0076e285b69b3731287f53abeb4e Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:10:58 +0900 Subject: [PATCH 24/60] media: apple: isp: Switch to threaded IRQs There's no reason to run all the command handling in hard IRQ context. Let's switch to threaded IRQs, which should simplify some things. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index cfb1aca37ebebe..7e3e02bf199182 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -92,6 +92,13 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t apple_isp_isr_thread(int irq, void *dev) +{ + struct apple_isp *isp = dev; + wake_up_interruptible_all(&isp->wait); ipc_chan_handle(isp, isp->chan_sm); @@ -116,7 +123,8 @@ static int isp_enable_irq(struct apple_isp *isp) { int err; - err = request_irq(isp->irq, apple_isp_isr, 0, "apple-isp", isp); + err = request_threaded_irq(isp->irq, apple_isp_isr, + apple_isp_isr_thread, 0, "apple-isp", isp); if (err < 0) { isp_err(isp, "failed to request IRQ#%u (%d)\n", isp->irq, err); return err; From 7da02f3cea5410a91bdfbb002a4f2c5e25809446 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 18:38:22 +0900 Subject: [PATCH 25/60] media: apple: isp: Remove ioread/iowrite and stop doing raw address translation Translating IOVAs via the DART and then trying to access physical memory directly is slow and error-prone. We know what surfaces IOVAs are supposed to be part of, so we can use the surface vmap to access the contents. Where we get an IOVA from the firmware, assert that it is within the expected range before accessing it. Since we're using threaded IRQs now, this also lets us get rid of the deferred vmap. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 2 +- drivers/media/platform/apple/isp/isp-cmd.c | 5 +- drivers/media/platform/apple/isp/isp-drv.h | 5 + drivers/media/platform/apple/isp/isp-fw.c | 69 ++++++++++-- drivers/media/platform/apple/isp/isp-fw.h | 9 ++ drivers/media/platform/apple/isp/isp-iommu.c | 6 -- drivers/media/platform/apple/isp/isp-iommu.h | 15 --- drivers/media/platform/apple/isp/isp-ipc.c | 105 +++++++++---------- drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 9 files changed, 129 insertions(+), 89 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 593b780ab73b15..abdc9e345933d8 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -323,7 +323,7 @@ static int isp_ch_load_setfile(struct apple_isp *isp, u32 ch) return -EINVAL; } - isp_iowrite(isp, isp->data_surf->iova, (void *)fw->data, setfile->size); + memcpy(isp->data_surf->virt, (void *)fw->data, setfile->size); release_firmware(fw); return isp_cmd_ch_set_file_load(isp, ch, isp->data_surf->iova, diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 1e812400e52f7d..1166f0990830ed 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -24,7 +24,7 @@ static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) req->arg1 = insize; req->arg2 = outsize; - isp_iowrite(isp, isp->cmd_iova, args, insize); + memcpy(isp->cmd_virt, args, insize); err = ipc_chan_send(isp, chan, CISP_TIMEOUT); if (err) { u64 opcode; @@ -45,7 +45,8 @@ static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, int err = cisp_send(isp, args, insize, outsize); if (err) return err; - isp_ioread(isp, isp->cmd_iova, args, outsize); + + memcpy(args, isp->cmd_virt, outsize); return 0; } diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 926c921849544a..26b9ee0e4d709f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -32,6 +32,7 @@ struct isp_surf { struct drm_mm_node *mm; struct list_head head; u64 size; + u64 type; u32 num_pages; struct page **pages; struct sg_table sgt; @@ -60,6 +61,7 @@ struct isp_channel { u32 num; u64 size; dma_addr_t iova; + void *virt; u32 doorbell; u32 cursor; spinlock_t lock; @@ -210,6 +212,8 @@ struct apple_isp { struct isp_surf *ipc_surf; struct isp_surf *extra_surf; struct isp_surf *data_surf; + struct isp_surf *log_surf; + struct isp_surf *bt_surf; struct list_head gc; struct workqueue_struct *wq; @@ -225,6 +229,7 @@ struct apple_isp { wait_queue_head_t wait; dma_addr_t cmd_iova; + void *cmd_virt; unsigned long state; spinlock_t buf_lock; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 7e3e02bf199182..1cae66c2f0e126 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright 2023 Eileen Yoon */ +#include "isp-fw.h" + #include #include @@ -37,6 +39,35 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } +void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, + dma_addr_t iova, size_t size) +{ + dma_addr_t end = iova + size; + if (!surf) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): No surface\n", + (long long)iova, size); + return NULL; + } + + if (end < iova || iova < surf->iova || + end > (surf->iova + surf->size)) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): Out of bounds\n", + (long long)iova, size); + return NULL; + } + + if (!surf->virt) { + dev_err(isp->dev, + "Failed to translate IPC iova 0x%llx (0x%zx): No VMap\n", + (long long)iova, size); + return NULL; + } + + return surf->virt + (iova - surf->iova); +} + struct isp_firmware_bootargs { u32 pad_0[2]; u64 ipc_iova; @@ -231,6 +262,8 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp) isp_err(isp, "failed to alloc shared surface for ipc\n"); return -ENOMEM; } + dev_info(isp->dev, "IPC surface iova: 0x%llx\n", + (long long)isp->ipc_surf->iova); isp->data_surf = isp_alloc_surface_vmap(isp, ISP_FIRMWARE_DATA_SIZE); if (!isp->data_surf) { @@ -238,6 +271,8 @@ int apple_isp_alloc_firmware_surface(struct apple_isp *isp) isp_free_surface(isp, isp->ipc_surf); return -ENOMEM; } + dev_info(isp->dev, "Data surface iova: 0x%llx\n", + (long long)isp->data_surf->iova); return 0; } @@ -257,6 +292,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) { struct isp_firmware_bootargs args; dma_addr_t args_iova; + void *args_virt; int err, retries; u32 num_ipc_chans = isp_gpio_read32(isp, ISP_GPIO_0); @@ -280,7 +316,9 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) } args_iova = isp->ipc_surf->iova + args_offset + 0x40; + args_virt = isp->ipc_surf->virt + args_offset + 0x40; isp->cmd_iova = args_iova + sizeof(args) + 0x40; + isp->cmd_virt = args_virt + sizeof(args) + 0x40; memset(&args, 0, sizeof(args)); args.ipc_iova = isp->ipc_surf->iova; @@ -294,7 +332,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) args.unk7 = 0x1; // 0? args.unk_iova1 = args_iova + sizeof(args) - 0xc; args.unk9 = 0x3; - isp_iowrite(isp, args_iova, &args, sizeof(args)); + memcpy(args_virt, &args, sizeof(args)); isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); @@ -354,7 +392,15 @@ static void isp_free_channel_info(struct apple_isp *isp) static int isp_fill_channel_info(struct apple_isp *isp) { u64 table_iova = isp_gpio_read32(isp, ISP_GPIO_0) | - ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; + ((u64)isp_gpio_read32(isp, ISP_GPIO_1)) << 32; + void *table_virt = apple_isp_ipc_translate( + isp, table_iova, + sizeof(struct isp_chan_desc) * isp->num_ipc_chans); + + if (!table_virt) { + dev_err(isp->dev, "Failed to find channel table\n"); + return -EIO; + } isp->ipc_chans = kcalloc(isp->num_ipc_chans, sizeof(struct isp_channel *), GFP_KERNEL); @@ -363,14 +409,14 @@ static int isp_fill_channel_info(struct apple_isp *isp) for (int i = 0; i < isp->num_ipc_chans; i++) { struct isp_chan_desc desc; - dma_addr_t desc_iova = table_iova + (i * sizeof(desc)); + void *desc_virt = table_virt + (i * sizeof(desc)); struct isp_channel *chan = kzalloc(sizeof(struct isp_channel), GFP_KERNEL); if (!chan) goto out; isp->ipc_chans[i] = chan; - isp_ioread(isp, desc_iova, &desc, sizeof(desc)); + memcpy(&desc, desc_virt, sizeof(desc)); chan->name = kstrdup(desc.name, GFP_KERNEL); chan->type = desc.type; chan->src = desc.src; @@ -378,9 +424,16 @@ static int isp_fill_channel_info(struct apple_isp *isp) chan->num = desc.num; chan->size = desc.num * ISP_IPC_MESSAGE_SIZE; chan->iova = desc.iova; + chan->virt = + apple_isp_ipc_translate(isp, desc.iova, chan->size); chan->cursor = 0; spin_lock_init(&chan->lock); + if (!chan->virt) { + dev_err(isp->dev, "Failed to find channel buffer\n"); + goto out; + } + if ((chan->type != ISP_IPC_CHAN_TYPE_COMMAND) && (chan->type != ISP_IPC_CHAN_TYPE_REPLY) && (chan->type != ISP_IPC_CHAN_TYPE_REPORT)) { @@ -438,11 +491,11 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) continue; for (int j = 0; j < chan->num; j++) { struct isp_message msg; - dma_addr_t msg_iova = chan->iova + (j * sizeof(msg)); + void *msg_virt = chan->virt + (j * sizeof(msg)); memset(&msg, 0, sizeof(msg)); msg.arg0 = ISP_IPC_FLAG_ACK; - isp_iowrite(isp, msg_iova, &msg, sizeof(msg)); + memcpy(msg_virt, &msg, sizeof(msg)); } } wmb(); @@ -546,6 +599,10 @@ static int isp_start_command_processor(struct apple_isp *isp) static void isp_collect_gc_surface(struct apple_isp *isp) { struct isp_surf *tmp, *surf; + + isp->log_surf = NULL; + isp->bt_surf = NULL; + list_for_each_entry_safe_reverse(surf, tmp, &isp->gc, head) { isp_dbg(isp, "freeing iova: 0x%llx size: 0x%llx virt: %pS\n", surf->iova, surf->size, (void *)surf->virt); diff --git a/drivers/media/platform/apple/isp/isp-fw.h b/drivers/media/platform/apple/isp/isp-fw.h index 264717793cea02..974216f0989f91 100644 --- a/drivers/media/platform/apple/isp/isp-fw.h +++ b/drivers/media/platform/apple/isp/isp-fw.h @@ -12,4 +12,13 @@ void apple_isp_free_firmware_surface(struct apple_isp *isp); int apple_isp_firmware_boot(struct apple_isp *isp); void apple_isp_firmware_shutdown(struct apple_isp *isp); +void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, + dma_addr_t iova, size_t size); + +static inline void *apple_isp_ipc_translate(struct apple_isp *isp, + dma_addr_t iova, size_t size) +{ + return apple_isp_translate(isp, isp->ipc_surf, iova, size); +} + #endif /* __ISP_FW_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 7a7f24aa0174ba..36a6322d6601d8 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -212,12 +212,6 @@ void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf) } } -void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova) -{ - phys_addr_t phys = iommu_iova_to_phys(isp->domain, iova); - return phys_to_virt(phys); -} - int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, struct sg_table *sgt, u64 size) { diff --git a/drivers/media/platform/apple/isp/isp-iommu.h b/drivers/media/platform/apple/isp/isp-iommu.h index 326cf7c12aa745..b99a182e284b72 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.h +++ b/drivers/media/platform/apple/isp/isp-iommu.h @@ -12,21 +12,6 @@ struct isp_surf *__isp_alloc_surface(struct apple_isp *isp, u64 size, bool gc); struct isp_surf *isp_alloc_surface_vmap(struct apple_isp *isp, u64 size); int isp_surf_vmap(struct apple_isp *isp, struct isp_surf *surf); void isp_free_surface(struct apple_isp *isp, struct isp_surf *surf); -void *isp_iotranslate(struct apple_isp *isp, dma_addr_t iova); - -static inline void isp_ioread(struct apple_isp *isp, dma_addr_t iova, - void *data, u64 size) -{ - void *virt = isp_iotranslate(isp, iova); - memcpy(data, virt, size); -} - -static inline void isp_iowrite(struct apple_isp *isp, dma_addr_t iova, - void *data, u64 size) -{ - void *virt = isp_iotranslate(isp, iova); - memcpy(virt, data, size); -} int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, struct sg_table *sgt, u64 size); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 14249a44798ba5..00bd7642177a59 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -4,6 +4,7 @@ #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-regs.h" +#include "isp-fw.h" #define ISP_IPC_FLAG_TERMINAL_ACK 0x3 #define ISP_IPC_BUFEXC_STAT_META_OFFSET 0x10 @@ -54,16 +55,16 @@ struct isp_bufexc_stat { } __packed; static_assert(sizeof(struct isp_bufexc_stat) == ISP_IPC_BUFEXC_STAT_SIZE); -static inline dma_addr_t chan_msg_iova(struct isp_channel *chan, u32 index) +static inline void *chan_msg_virt(struct isp_channel *chan, u32 index) { - return chan->iova + (index * ISP_IPC_MESSAGE_SIZE); + return chan->virt + (index * ISP_IPC_MESSAGE_SIZE); } static inline void chan_read_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - isp_ioread(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); + memcpy(msg, chan_msg_virt(chan, index), sizeof(*msg)); } static inline void chan_read_msg(struct apple_isp *isp, @@ -77,7 +78,7 @@ static inline void chan_write_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - isp_iowrite(isp, chan_msg_iova(chan, index), msg, sizeof(*msg)); + memcpy(chan_msg_virt(chan, index), msg, sizeof(*msg)); } static inline void chan_write_msg(struct apple_isp *isp, @@ -191,10 +192,14 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) char buf[512]; dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; u32 size = req->arg1; - if (iova && size && test_bit(ISP_STATE_LOGGING, &isp->state)) { - size = min_t(u32, size, 512); - isp_ioread(isp, iova, buf, size); - isp_dbg(isp, "ISPASC: %.*s", size, buf); + if (iova && size && size < sizeof(buf) && + test_bit(ISP_STATE_LOGGING, &isp->state)) { + void *p = apple_isp_translate(isp, isp->log_surf, iova, size); + if (p) { + size = min_t(u32, size, 512); + memcpy(buf, p, size); + isp_dbg(isp, "ISPASC: %.*s", size, buf); + } } #endif @@ -205,55 +210,15 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) return 0; } -/* The kernel accesses exactly two dynamically allocated shared surfaces: - * 1) LOG: Surface for terminal logs. Optional, only enabled in debug builds. - * 2) STAT: Surface for BUFT2H rendered frame stat buffer. We isp_ioread() in - * the BUFT2H ISR below. Since the BUFT2H IRQ is triggered by the BUF_H2T - * doorbell, the STAT vmap must complete before the first buffer submission - * under VIDIOC_STREAMON(). The CISP_CMD_PRINT_ENABLE completion depends on the - * STAT buffer SHAREDMALLOC ISR, which is part of the firmware initialization - * sequence. We also call flush_workqueue(), so a fault should not occur. - */ -static void sm_malloc_deferred_worker(struct work_struct *work) -{ - struct isp_sm_deferred_work *dwork = - container_of(work, struct isp_sm_deferred_work, work); - struct apple_isp *isp = dwork->isp; - struct isp_surf *surf = dwork->surf; - int err; - - err = isp_surf_vmap(isp, surf); /* Can't vmap in interrupt ctx */ - if (err < 0) { - isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", - surf->iova, surf->size); - goto out; - } - -#ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. - */ - if (!test_bit(ISP_STATE_LOGGING, &isp->state)) - set_bit(ISP_STATE_LOGGING, &isp->state); -#endif - -out: - kfree(dwork); -} - int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) { struct isp_message *req = &chan->req, *rsp = &chan->rsp; + int err; if (req->arg0 == 0x0) { struct isp_sm_deferred_work *dwork; struct isp_surf *surf; - dwork = kzalloc(sizeof(*dwork), GFP_KERNEL); - if (!dwork) - return -ENOMEM; - dwork->isp = isp; - surf = isp_alloc_surface_gc(isp, req->arg1); if (!surf) { isp_err(isp, "failed to alloc requested size 0x%llx\n", @@ -261,19 +226,36 @@ int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) kfree(dwork); return -ENOMEM; } - dwork->surf = surf; + surf->type = req->arg2; rsp->arg0 = surf->iova | ISP_IPC_FLAG_ACK; rsp->arg1 = 0x0; rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ - INIT_WORK(&dwork->work, sm_malloc_deferred_worker); - if (!queue_work(isp->wq, &dwork->work)) { - isp_err(isp, "failed to queue deferred work\n"); - isp_free_surface(isp, surf); - kfree(dwork); - return -ENOMEM; + err = isp_surf_vmap(isp, surf); + if (err < 0) { + isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", + surf->iova, surf->size); + } else { + switch (surf->type) { + case 0x4c4f47: /* "LOG" */ + isp->log_surf = surf; + break; + case 0x4d495343: /* "MISC" */ + /* Hacky... maybe there's a better way to identify this surface? */ + if (surf->size == 0xc000) + isp->bt_surf = surf; + break; + } } + +#ifdef APPLE_ISP_DEBUG + /* Only enabled in debug builds so it shouldn't matter, but + * the LOG surface is always the first surface requested. + */ + if (!test_bit(ISP_STATE_LOGGING, &isp->state)) + set_bit(ISP_STATE_LOGGING, &isp->state); +#endif /* To the gc it goes... */ } else { @@ -302,8 +284,15 @@ int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) /* No need to read the whole struct */ u64 meta_iova; - isp_ioread(isp, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, &meta_iova, - sizeof(meta_iova)); + u64 *p_meta_iova = apple_isp_translate( + isp, isp->bt_surf, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, + sizeof(u64)); + + if (!p_meta_iova) { + dev_err(isp->dev, "Failed to find bufexc stat meta\n"); + return -EIO; + } + meta_iova = *p_meta_iova; spin_lock(&isp->buf_lock); list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index c133544752e66a..8f3c6ece88fac3 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -91,7 +91,7 @@ static int isp_submit_buffers(struct apple_isp *isp) req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - isp_iowrite(isp, req->arg0, args, sizeof(*args)); + memcpy(isp->cmd_virt, args, sizeof(*args)); err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); if (err) { /* If we fail, consider the buffer not submitted. */ From 539b8c72cdfe096b4e11624ad1bd8e9df614e2a9 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:18:40 +0900 Subject: [PATCH 26/60] media: apple: isp: Propagate EINTR from firmware loads Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index abdc9e345933d8..9ccdc2a1304bed 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -340,6 +340,10 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) { dev_err(isp->dev, "warning: calibration data not loaded: %d\n", err); + + /* If this failed due to a signal, propagate */ + if (err == -EINTR) + return err; } if (isp->hw->gen >= ISP_GEN_T8112) { From f2886e29371b07bed2a7b33451b0b2cfb43104e1 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:19:12 +0900 Subject: [PATCH 27/60] media: apple: isp: Implement posted commands Useful for shutdown type commands which may not be acked... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cmd.c | 11 ++++++----- drivers/media/platform/apple/isp/isp-ipc.c | 3 +++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 1166f0990830ed..26ae639b3a63d9 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -10,11 +10,12 @@ #define CISP_OPCODE_GET(x) (((u64)(x)) >> CISP_OPCODE_SHIFT) #define CISP_TIMEOUT msecs_to_jiffies(3000) -#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0)) -#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a))) +#define CISP_SEND_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, CISP_TIMEOUT)) +#define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), CISP_TIMEOUT)) #define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) +#define CISP_POST_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, 0)) -static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) +static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize, int timeout) { struct isp_channel *chan = isp->chan_io; struct isp_message *req = &chan->req; @@ -25,7 +26,7 @@ static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize) req->arg2 = outsize; memcpy(isp->cmd_virt, args, insize); - err = ipc_chan_send(isp, chan, CISP_TIMEOUT); + err = ipc_chan_send(isp, chan, timeout); if (err) { u64 opcode; memcpy(&opcode, args, sizeof(opcode)); @@ -42,7 +43,7 @@ static int cisp_send_read(struct apple_isp *isp, void *args, u32 insize, u32 outsize) { /* TODO do I need to lock the iova space? */ - int err = cisp_send(isp, args, insize, outsize); + int err = cisp_send(isp, args, insize, outsize, CISP_TIMEOUT); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 00bd7642177a59..56a482c17424cb 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -168,6 +168,9 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + if (!timeout) + return 0; + t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), timeout); if (t == 0) { From 0c461c320c153dd398994b11220e1961c30a67af Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Fri, 29 Sep 2023 19:21:38 +0900 Subject: [PATCH 28/60] media: apple: isp: Add STOP and POWER_DOWN commands Not sure if these work properly yet, but worth having them to experiment. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cmd.c | 17 +++++++++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 14 ++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 26ae639b3a63d9..bd82d266522dc0 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -60,6 +60,23 @@ int isp_cmd_start(struct apple_isp *isp, u32 mode) return CISP_SEND_IN(isp, args); } +int isp_cmd_stop(struct apple_isp *isp, u32 mode) +{ + struct cmd_stop args = { + .opcode = CISP_OPCODE(CISP_CMD_STOP), + .mode = mode, + }; + return CISP_SEND_IN(isp, args); +} + +int isp_cmd_power_down(struct apple_isp *isp) +{ + struct cmd_power_down args = { + .opcode = CISP_OPCODE(CISP_CMD_POWER_DOWN), + }; + return CISP_POST_INOUT(isp, args); +} + int isp_cmd_suspend(struct apple_isp *isp) { struct cmd_suspend args = { diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 1586df89f1cdab..2de2a49f2cd398 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -12,6 +12,7 @@ #define CISP_CMD_PRINT_ENABLE 0x0004 #define CISP_CMD_BUILDINFO 0x0006 #define CISP_CMD_GET_BES_PARAM 0x000f +#define CISP_CMD_POWER_DOWN 0x0010 #define CISP_CMD_SET_ISP_PMU_BASE 0x0011 #define CISP_CMD_PMP_CTRL_SET 0x001c #define CISP_CMD_TRACE_ENABLE 0x001d @@ -130,6 +131,17 @@ struct cmd_start { } __packed; static_assert(sizeof(struct cmd_start) == 0xc); +struct cmd_stop { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_stop) == 0xc); + +struct cmd_power_down { + u64 opcode; +} __packed; +static_assert(sizeof(struct cmd_power_down) == 0x8); + struct cmd_suspend { u64 opcode; } __packed; @@ -221,6 +233,8 @@ struct cmd_ipc_endpoint_set2 { static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); int isp_cmd_start(struct apple_isp *isp, u32 mode); +int isp_cmd_stop(struct apple_isp *isp, u32 mode); +int isp_cmd_power_down(struct apple_isp *isp); int isp_cmd_suspend(struct apple_isp *isp); int isp_cmd_print_enable(struct apple_isp *isp, u32 enable); int isp_cmd_trace_enable(struct apple_isp *isp, u32 enable); From 0d38cba1a604a1765270c8a542eaca25d088c57b Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 00:15:27 +0900 Subject: [PATCH 29/60] media: apple: isp: Maybe fix some DMA ordering issues Maybe. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 4 ++-- drivers/media/platform/apple/isp/isp-ipc.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 1cae66c2f0e126..16caee6a7c4c43 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -336,7 +336,7 @@ static int isp_firmware_boot_stage2(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_0, args_iova); isp_gpio_write32(isp, ISP_GPIO_1, args_iova >> 32); - wmb(); + dma_wmb(); /* Wait for ISP_GPIO_7 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_7, 0xf7fbdff9); @@ -498,7 +498,7 @@ static int isp_firmware_boot_stage3(struct apple_isp *isp) memcpy(msg_virt, &msg, sizeof(msg)); } } - wmb(); + dma_wmb(); /* Wait for ISP_GPIO_3 to 0x8042006 -> 0x0 */ isp_gpio_write32(isp, ISP_GPIO_3, 0x8042006); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 56a482c17424cb..21c494f49ebc5f 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -78,7 +78,14 @@ static inline void chan_write_msg_index(struct apple_isp *isp, struct isp_channel *chan, struct isp_message *msg, u32 index) { - memcpy(chan_msg_virt(chan, index), msg, sizeof(*msg)); + u64 *p0 = chan_msg_virt(chan, index); + memcpy(p0 + 1, &msg->arg1, sizeof(*msg) - 8); + + /* Make sure we write arg0 last, since that indicates message validity. */ + + dma_wmb(); + *p0 = msg->arg0; + dma_wmb(); } static inline void chan_write_msg(struct apple_isp *isp, @@ -164,7 +171,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, long t; chan_write_msg(isp, chan, &chan->req); - wmb(); + dma_wmb(); isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); From 33fb89fe36291069155c4e1ebb5e9ac0635dd417 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 00:15:41 +0900 Subject: [PATCH 30/60] media: apple: isp: Make channel sends not interruptible Otherwise processes receiving a signal will break our command flows. Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 6 +++--- drivers/media/platform/apple/isp/isp-ipc.c | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 16caee6a7c4c43..b26e29a103e002 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -130,15 +130,15 @@ static irqreturn_t apple_isp_isr_thread(int irq, void *dev) { struct apple_isp *isp = dev; - wake_up_interruptible_all(&isp->wait); + wake_up_all(&isp->wait); ipc_chan_handle(isp, isp->chan_sm); - wake_up_interruptible_all(&isp->wait); /* Some commands depend on sm */ + wake_up_all(&isp->wait); /* Some commands depend on sm */ ipc_chan_handle(isp, isp->chan_tm); ipc_chan_handle(isp, isp->chan_bt); - wake_up_interruptible_all(&isp->wait); + wake_up_all(&isp->wait); return IRQ_HANDLED; } diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 21c494f49ebc5f..c63babfb9951b6 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -178,8 +178,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, if (!timeout) return 0; - t = wait_event_interruptible_timeout(isp->wait, chan_tx_done(isp, chan), - timeout); + t = wait_event_timeout(isp->wait, chan_tx_done(isp, chan), timeout); if (t == 0) { dev_err(isp->dev, "%s: timed out on request [0x%llx, 0x%llx, 0x%llx]\n", From 08d18fe2f2ec2f2d6f43124ee2f5b1ecc587c6d3 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 08:11:20 +0200 Subject: [PATCH 31/60] media: apple: isp: Use a second region for MBOX_IRQ_{DOORBELL,ACK} t8112 uses a different register layout. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-drv.c | 6 ++++++ drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 2 +- drivers/media/platform/apple/isp/isp-ipc.c | 4 ++-- drivers/media/platform/apple/isp/isp-regs.h | 13 +++++++++---- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index a887e342115311..788fe18a66eb6f 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -276,6 +276,12 @@ static int apple_isp_probe(struct platform_device *pdev) goto detach_genpd; } + isp->mbox2 = devm_platform_ioremap_resource_byname(pdev, "mbox2"); + if (IS_ERR(isp->mbox2)) { + err = PTR_ERR(isp->mbox2); + goto detach_genpd; + } + isp->irq = platform_get_irq(pdev, 0); if (isp->irq < 0) { err = isp->irq; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 26b9ee0e4d709f..4d3b1bd7603aea 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -199,6 +199,7 @@ struct apple_isp { void __iomem *coproc; void __iomem *mbox; void __iomem *gpio; + void __iomem *mbox2; struct iommu_domain *domain; unsigned long shift; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index b26e29a103e002..053aabd8f54dd3 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -120,7 +120,7 @@ static irqreturn_t apple_isp_isr(int irq, void *dev) { struct apple_isp *isp = dev; - isp_mbox_write32(isp, ISP_MBOX_IRQ_ACK, + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_ACK, isp_mbox_read32(isp, ISP_MBOX_IRQ_INTERRUPT)); return IRQ_WAKE_THREAD; diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index c63babfb9951b6..0475b3cf2699ee 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -118,7 +118,7 @@ static int chan_handle_once(struct apple_isp *isp, struct isp_channel *chan) chan_write_msg(isp, chan, &chan->rsp); - isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_DOORBELL, chan->doorbell); chan_update_cursor(chan); @@ -173,7 +173,7 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, chan_write_msg(isp, chan, &chan->req); dma_wmb(); - isp_mbox_write32(isp, ISP_MBOX_IRQ_DOORBELL, chan->doorbell); + isp_mbox2_write32(isp, ISP_MBOX2_IRQ_DOORBELL, chan->doorbell); if (!timeout) return 0; diff --git a/drivers/media/platform/apple/isp/isp-regs.h b/drivers/media/platform/apple/isp/isp-regs.h index 3a99229f6d4c8f..7357fa10fa5483 100644 --- a/drivers/media/platform/apple/isp/isp-regs.h +++ b/drivers/media/platform/apple/isp/isp-regs.h @@ -23,10 +23,10 @@ #define ISP_COPROC_IRQ_MASK_4 0x1400a10 #define ISP_COPROC_IRQ_MASK_5 0x1400a14 -#define ISP_MBOX_IRQ_INTERRUPT 0x000 -#define ISP_MBOX_IRQ_ENABLE 0x004 -#define ISP_MBOX_IRQ_DOORBELL 0x3f0 -#define ISP_MBOX_IRQ_ACK 0x3fc +#define ISP_MBOX_IRQ_INTERRUPT 0x00 +#define ISP_MBOX_IRQ_ENABLE 0x04 +#define ISP_MBOX2_IRQ_DOORBELL 0x00 +#define ISP_MBOX2_IRQ_ACK 0x0c #define ISP_GPIO_0 0x00 #define ISP_GPIO_1 0x04 @@ -48,4 +48,9 @@ static inline void isp_mbox_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->mbox + reg); } +static inline void isp_mbox2_write32(struct apple_isp *isp, u32 reg, u32 val) +{ + writel(val, isp->mbox2 + reg); +} + #endif /* __ISP_REGS_H__ */ From e8f6ce51520fcec7cb4e86b5cb6e714bf5ab953f Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 08:27:10 +0200 Subject: [PATCH 32/60] media: apple: isp: t8112 HW config Not yet working. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-drv.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 788fe18a66eb6f..5ad2fddacb4d2a 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -415,19 +415,14 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .meta_size = ISP_META_SIZE_T8103, }; -static const struct apple_isp_hw apple_isp_hw_t8110 = { +static const struct apple_isp_hw apple_isp_hw_t8112 = { .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, - .dsid_count = 4, - .dsid_clr_base0 = 0x200014000, // TODO - .dsid_clr_base1 = 0x200054000, - .dsid_clr_base2 = 0x200094000, - .dsid_clr_base3 = 0x2000d4000, + // TODO: verify + .dsid_count = 1, + .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, - .dsid_clr_range1 = 0x1000, - .dsid_clr_range2 = 0x1000, - .dsid_clr_range3 = 0x1000, .clock_scratch = 0x23b3d0560, .clock_base = 0x0, @@ -465,6 +460,7 @@ static const struct apple_isp_hw apple_isp_hw_t6020 = { static const struct of_device_id apple_isp_of_match[] = { { .compatible = "apple,t8103-isp", .data = &apple_isp_hw_t8103 }, + { .compatible = "apple,t8112-isp", .data = &apple_isp_hw_t8112 }, { .compatible = "apple,t6000-isp", .data = &apple_isp_hw_t6000 }, { .compatible = "apple,t6020-isp", .data = &apple_isp_hw_t6020 }, {}, From fa2c4b6857932072beb32975910ba312deb1bab4 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 28 Sep 2023 20:45:18 +0200 Subject: [PATCH 33/60] media: apple: isp: Limit maximal number of buffers ISP (FW 12.3) on t6001 times out if more buffers than count in the buffer pool config are submitted before streaming is started. To avoid keeping track of the number of submitted buffers limit the number. 16 buffers / frames should be more than enough. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-cmd.c | 2 +- drivers/media/platform/apple/isp/isp-drv.h | 3 +++ drivers/media/platform/apple/isp/isp-v4l2.c | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index bd82d266522dc0..cbd9348f592dc2 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -395,7 +395,7 @@ int isp_cmd_ch_buffer_pool_config_set(struct apple_isp *isp, u32 chan, u16 type) .opcode = CISP_OPCODE(CISP_CMD_CH_BUFFER_POOL_CONFIG_SET), .chan = chan, .type = type, - .count = 16, + .count = ISP_MAX_BUFFERS, .meta_size0 = isp->hw->meta_size, .meta_size1 = isp->hw->meta_size, .unk0 = 0, diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 4d3b1bd7603aea..8269b772bbd1bd 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -23,6 +23,9 @@ #define ISP_META_SIZE_T8103 0x4640 #define ISP_META_SIZE_T8112 0x4840 +/* used to limit the user space buffers to the buffer_pool_config */ +#define ISP_MAX_BUFFERS 16 + enum isp_generation { ISP_GEN_T8103, ISP_GEN_T8112, diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 8f3c6ece88fac3..cd0fb613447bfb 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -11,6 +11,7 @@ #include "isp-cam.h" #include "isp-cmd.h" +#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-v4l2.h" @@ -143,6 +144,13 @@ static int isp_vb2_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, struct apple_isp *isp = vb2_get_drv_priv(vq); struct isp_format *fmt = isp_get_current_format(isp); + /* This is not strictly neccessary but makes it easy to enforce that + * at most 16 buffers are submitted at once. ISP on t6001 (FW 12.3) + * times out if more buffers are submitted than set in the buffer pool + * config before streaming is started. + */ + *nbuffers = min_t(unsigned int, *nbuffers, ISP_MAX_BUFFERS); + if (*num_planes) { if (sizes[0] < fmt->total_size) return -EINVAL; From 4863b2cee78c3fb227d13c3108d0ea5a33e02d80 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Sat, 30 Sep 2023 18:53:26 +0900 Subject: [PATCH 34/60] media: apple: isp: t8112 fixes... Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 4 ++-- drivers/media/platform/apple/isp/isp-cmd.c | 4 ++-- drivers/media/platform/apple/isp/isp-cmd.h | 2 +- drivers/media/platform/apple/isp/isp-drv.c | 12 ++++++++++-- drivers/media/platform/apple/isp/isp-drv.h | 2 ++ 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 9ccdc2a1304bed..4966fe64aac299 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -346,7 +346,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) return err; } - if (isp->hw->gen >= ISP_GEN_T8112) { + if (isp->hw->lpdp) { err = isp_cmd_ch_lpdp_hs_receiver_tuning_set(isp, ch, 1, 15); if (err) return err; @@ -395,7 +395,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_start(isp, ch); + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index cbd9348f592dc2..15a5ec22778ced 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -416,13 +416,13 @@ int isp_cmd_ch_buffer_pool_return(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } -int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan) +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan, u32 arg) { struct cmd_apple_ch_temporal_filter_start args = { .opcode = CISP_OPCODE(CISP_CMD_APPLE_CH_TEMPORAL_FILTER_START), .chan = chan, .unk_c = 1, - .unk_10 = 0, + .unk_10 = arg, }; return CISP_SEND_IN(isp, args); } diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 2de2a49f2cd398..718ae88045ac25 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -577,7 +577,7 @@ struct cmd_apple_ch_temporal_filter_disable { } __packed; static_assert(sizeof(struct cmd_apple_ch_temporal_filter_disable) == 0xc); -int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan); +int isp_cmd_apple_ch_temporal_filter_start(struct apple_isp *isp, u32 chan, u32 arg); int isp_cmd_apple_ch_temporal_filter_stop(struct apple_isp *isp, u32 chan); int isp_cmd_apple_ch_motion_history_start(struct apple_isp *isp, u32 chan); int isp_cmd_apple_ch_motion_history_stop(struct apple_isp *isp, u32 chan); diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 5ad2fddacb4d2a..dfcb4f02ebd9b8 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -246,6 +246,11 @@ static int apple_isp_probe(struct platform_device *pdev) return err; } + err = of_property_read_u32(dev->of_node, "apple,temporal-filter", + &isp->temporal_filter); + if (err) + isp->temporal_filter = 0; + err = apple_isp_init_presets(isp); if (err) { dev_err(dev, "failed to initialize presets\n"); @@ -385,6 +390,7 @@ static const struct apple_isp_hw apple_isp_hw_t8103 = { .bandwidth_size = 0x4, .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8103, }; @@ -412,6 +418,7 @@ static const struct apple_isp_hw apple_isp_hw_t6000 = { .bandwidth_size = 0x8, .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8103, }; @@ -419,7 +426,6 @@ static const struct apple_isp_hw apple_isp_hw_t8112 = { .gen = ISP_GEN_T8112, .pmu_base = 0x23b704000, - // TODO: verify .dsid_count = 1, .dsid_clr_base0 = 0x200f14000, .dsid_clr_range0 = 0x1000, @@ -433,7 +439,8 @@ static const struct apple_isp_hw apple_isp_hw_t8112 = { .bandwidth_bit = 0x0, .bandwidth_size = 0x8, - .scl1 = true, + .scl1 = false, + .lpdp = false, .meta_size = ISP_META_SIZE_T8112, }; @@ -455,6 +462,7 @@ static const struct apple_isp_hw apple_isp_hw_t6020 = { .bandwidth_size = 0x8, .scl1 = true, + .lpdp = true, .meta_size = ISP_META_SIZE_T8112, }; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 8269b772bbd1bd..b62d389442e810 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -111,6 +111,7 @@ struct apple_isp_hw { u32 meta_size; bool scl1; + bool lpdp; }; enum isp_sensor_id { @@ -178,6 +179,7 @@ struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; u32 platform_id; + u32 temporal_filter; struct isp_preset *presets; int num_presets; From efe227a2146350ce7e5fb8ce2bafb032b89c278e Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:18:25 +0900 Subject: [PATCH 35/60] media: apple: isp: Add flicker_sensor_set cmd Signed-off-by: Asahi Lina --- drivers/iommu/io-pgtable-dart.c | 2 +- drivers/media/platform/apple/isp/isp-cmd.c | 10 ++++++++++ drivers/media/platform/apple/isp/isp-cmd.h | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c index 74b1ef2b96bee1..91652cf91af379 100644 --- a/drivers/iommu/io-pgtable-dart.c +++ b/drivers/iommu/io-pgtable-dart.c @@ -140,7 +140,6 @@ static int dart_init_pte(struct dart_io_pgtable *data, pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_START, 0); pte |= FIELD_PREP(APPLE_DART_PTE_SUBPAGE_END, 0xfff); - pte |= APPLE_DART1_PTE_PROT_SP_DIS; pte |= APPLE_DART_PTE_VALID; for (i = 0; i < num_entries; i++) @@ -216,6 +215,7 @@ static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data, dart_iopte pte = 0; if (data->iop.fmt == APPLE_DART) { + pte |= APPLE_DART1_PTE_PROT_SP_DIS; if (!(prot & IOMMU_WRITE)) pte |= APPLE_DART1_PTE_PROT_NO_WRITE; if (!(prot & IOMMU_READ)) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 15a5ec22778ced..9c5808b4e831be 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -14,6 +14,7 @@ #define CISP_SEND_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), CISP_TIMEOUT)) #define CISP_SEND_OUT(x, a) (cisp_send_read((x), (a), sizeof(*a), sizeof(*a))) #define CISP_POST_IN(x, a) (cisp_send((x), &(a), sizeof(a), 0, 0)) +#define CISP_POST_INOUT(x, a) (cisp_send((x), &(a), sizeof(a), sizeof(a), 0)) static int cisp_send(struct apple_isp *isp, void *args, u32 insize, u32 outsize, int timeout) { @@ -204,6 +205,15 @@ int isp_cmd_ch_stop(struct apple_isp *isp, u32 chan) return CISP_SEND_IN(isp, args); } +int isp_cmd_flicker_sensor_set(struct apple_isp *isp, u32 mode) +{ + struct cmd_flicker_sensor_set args = { + .opcode = CISP_OPCODE(CISP_CMD_FLICKER_SENSOR_SET), + .mode = mode, + }; + return CISP_SEND_INOUT(isp, args); +} + int isp_cmd_ch_info_get(struct apple_isp *isp, u32 chan, struct cmd_ch_info *args) { diff --git a/drivers/media/platform/apple/isp/isp-cmd.h b/drivers/media/platform/apple/isp/isp-cmd.h index 718ae88045ac25..5a3c8cd9177e48 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.h +++ b/drivers/media/platform/apple/isp/isp-cmd.h @@ -232,6 +232,12 @@ struct cmd_ipc_endpoint_set2 { } __packed; static_assert(sizeof(struct cmd_ipc_endpoint_set2) == 0x30); +struct cmd_flicker_sensor_set { + u64 opcode; + u32 mode; +} __packed; +static_assert(sizeof(struct cmd_flicker_sensor_set) == 0xc); + int isp_cmd_start(struct apple_isp *isp, u32 mode); int isp_cmd_stop(struct apple_isp *isp, u32 mode); int isp_cmd_power_down(struct apple_isp *isp); @@ -253,6 +259,7 @@ int isp_cmd_pmp_ctrl_set(struct apple_isp *isp, u64 clock_scratch, u8 bandwidth_bit, u8 bandwidth_size); int isp_cmd_fid_enter(struct apple_isp *isp); int isp_cmd_fid_exit(struct apple_isp *isp); +int isp_cmd_flicker_sensor_set(struct apple_isp *isp, u32 mode); struct cmd_ch_start { u64 opcode; From 49924bbb5cdd1accf86718322a62fdaf4df2eb2c Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:18:46 +0900 Subject: [PATCH 36/60] media: apple: isp: Minor changes to cam flow Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-cam.c | 30 ++++++++++++++++++---- drivers/media/platform/apple/isp/isp-cam.h | 1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 4966fe64aac299..69b67df5697501 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -289,6 +289,12 @@ int apple_isp_detect_camera(struct apple_isp *isp) } err = isp_detect_camera(isp); + + isp_cmd_flicker_sensor_set(isp, 0); + + isp_cmd_ch_stop(isp, 0); + isp_cmd_ch_buffer_return(isp, isp->current_ch); + apple_isp_firmware_shutdown(isp); return err; @@ -335,6 +341,8 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) struct isp_format *fmt = isp_get_format(isp, ch); int err; + isp_cmd_flicker_sensor_set(isp, 0); + /* The setfile isn't requisite but then we don't get calibration */ err = isp_ch_load_setfile(isp, ch); if (err) { @@ -356,16 +364,16 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_buffer_recycle_mode_set( - isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); + err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); if (err) return err; - err = isp_cmd_ch_buffer_recycle_start(isp, ch); + err = isp_cmd_ch_buffer_recycle_mode_set( + isp, ch, CISP_BUFFER_RECYCLE_MODE_EMPTY_ONLY); if (err) return err; - err = isp_cmd_ch_camera_config_select(isp, ch, fmt->preset->index); + err = isp_cmd_ch_buffer_recycle_start(isp, ch); if (err) return err; @@ -431,7 +439,19 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN); + err = isp_cmd_ch_ae_frame_rate_min_set(isp, ch, ISP_FRAME_RATE_DEN2); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->hw->temporal_filter); + if (err) + return err; + + err = isp_cmd_apple_ch_motion_history_start(isp, ch); + if (err) + return err; + + err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); if (err) return err; diff --git a/drivers/media/platform/apple/isp/isp-cam.h b/drivers/media/platform/apple/isp/isp-cam.h index 126e5806c8c416..f4fa4224c7a934 100644 --- a/drivers/media/platform/apple/isp/isp-cam.h +++ b/drivers/media/platform/apple/isp/isp-cam.h @@ -8,6 +8,7 @@ #define ISP_FRAME_RATE_NUM 256 #define ISP_FRAME_RATE_DEN 7680 +#define ISP_FRAME_RATE_DEN2 3840 int apple_isp_detect_camera(struct apple_isp *isp); From de4ee228c81265b02551188e2c2b31e6c0169614 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:21:54 +0900 Subject: [PATCH 37/60] media: apple: isp: Make sub-pmdomain handling explicit Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.c | 11 ++++-- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 45 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index dfcb4f02ebd9b8..45597e0361fa8a 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -54,6 +54,12 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) return -ENOMEM; for (int i = 0; i < isp->pd_count; i++) { + int flags = DL_FLAG_STATELESS; + + /* Primary power domain uses RPM integration */ + if (i == 0) + flags |= DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE; + isp->pd_dev[i] = dev_pm_domain_attach_by_id(dev, i); if (IS_ERR(isp->pd_dev[i])) { apple_isp_detach_genpd(isp); @@ -61,9 +67,8 @@ static int apple_isp_attach_genpd(struct apple_isp *isp) } isp->pd_link[i] = - device_link_add(dev, isp->pd_dev[i], - DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); + device_link_add(dev, isp->pd_dev[i], flags); + if (!isp->pd_link[i]) { apple_isp_detach_genpd(isp); return -EINVAL; diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index b62d389442e810..775a435c4a06ad 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -198,6 +198,7 @@ struct apple_isp { int pd_count; struct device **pd_dev; struct device_link **pd_link; + bool pds_active; int irq; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 053aabd8f54dd3..3378472fcccbdb 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -39,6 +39,46 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } +int apple_isp_power_up_domains(struct apple_isp *isp) +{ + int ret; + + if (isp->pds_active) + return 0; + + for (int i = 1; i < isp->pd_count; i++) { + ret = pm_runtime_get_sync(isp->pd_dev[i]); + if (ret < 0) { + dev_err(isp->dev, + "Failed to power up power domain %d: %d\n", i, ret); + while (--i != 1) + pm_runtime_put_sync(isp->pd_dev[i]); + return ret; + } + } + + isp->pds_active = true; + + return 0; +} + +void apple_isp_power_down_domains(struct apple_isp *isp) +{ + int ret; + + if (!isp->pds_active) + return; + + for (int i = isp->pd_count - 1; i >= 1; i--) { + ret = pm_runtime_put_sync(isp->pd_dev[i]); + if (ret < 0) + dev_err(isp->dev, + "Failed to power up power domain %d: %d\n", i, ret); + } + + isp->pds_active = false; +} + void *apple_isp_translate(struct apple_isp *isp, struct isp_surf *surf, dma_addr_t iova, size_t size) { @@ -207,11 +247,16 @@ static int isp_reset_coproc(struct apple_isp *isp) static void isp_firmware_shutdown_stage1(struct apple_isp *isp) { isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x0); + + apple_isp_power_down_domains(isp); } static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; + err = apple_isp_power_up_domains(isp); + if (err < 0) + return err; err = isp_reset_coproc(isp); if (err < 0) From 22e09ad80ad502490c7a811810f721f3400e633c Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:22:49 +0900 Subject: [PATCH 38/60] media: apple: isp: Zero out pages allocated to ISP Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index 36a6322d6601d8..c1897383b4f128 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -21,7 +21,7 @@ static int isp_surf_alloc_pages(struct isp_surf *surf) return -ENOMEM; for (u32 i = 0; i < surf->num_pages; i++) { - surf->pages[i] = alloc_page(GFP_KERNEL); + surf->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO); if (surf->pages[i] == NULL) goto free_pages; } From 85aed139d3271b5be81069140b7b8b227aa04683 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:22:58 +0900 Subject: [PATCH 39/60] media: apple: isp: Use cached IOMMU mappings Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-iommu.c b/drivers/media/platform/apple/isp/isp-iommu.c index c1897383b4f128..13db2fca78dd94 100644 --- a/drivers/media/platform/apple/isp/isp-iommu.c +++ b/drivers/media/platform/apple/isp/isp-iommu.c @@ -112,7 +112,7 @@ static int isp_surf_iommu_map(struct apple_isp *isp, struct isp_surf *surf) } size = iommu_map_sgtable(isp->domain, surf->iova, &surf->sgt, - IOMMU_READ | IOMMU_WRITE); + IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); if (size < surf->size) { dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", surf->iova); @@ -230,7 +230,7 @@ int apple_isp_iommu_map_sgt(struct apple_isp *isp, struct isp_surf *surf, } mapped = iommu_map_sgtable(isp->domain, surf->iova, sgt, - IOMMU_READ | IOMMU_WRITE); + IOMMU_READ | IOMMU_WRITE | IOMMU_CACHE); if (mapped < surf->size) { dev_err(isp->dev, "failed to iommu_map sgt to iova 0x%llx\n", surf->iova); From 758788821521dec64c477555ad728fa93ae0e3e2 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:23:42 +0900 Subject: [PATCH 40/60] media: apple: isp: Rework meta surface handling & buffer return Now we keep track of meta surfaces independently, and always allocate 16 of them, plus handle buffer return messages more correctly. Fixes t8112 asserts (for some reason). Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-drv.h | 3 +- drivers/media/platform/apple/isp/isp-fw.c | 1 + drivers/media/platform/apple/isp/isp-ipc.c | 42 ---- drivers/media/platform/apple/isp/isp-ipc.h | 1 - drivers/media/platform/apple/isp/isp-v4l2.c | 239 ++++++++++++++------ drivers/media/platform/apple/isp/isp-v4l2.h | 1 + 6 files changed, 176 insertions(+), 111 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 775a435c4a06ad..31c527532aebac 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -43,6 +43,7 @@ struct isp_surf { void *virt; refcount_t refcount; bool gc; + bool submitted; }; struct isp_message { @@ -221,6 +222,7 @@ struct apple_isp { struct isp_surf *data_surf; struct isp_surf *log_surf; struct isp_surf *bt_surf; + struct isp_surf *meta_surfs[ISP_MAX_BUFFERS]; struct list_head gc; struct workqueue_struct *wq; @@ -252,7 +254,6 @@ struct isp_buffer { struct vb2_v4l2_buffer vb; struct list_head link; struct isp_surf surfs[VB2_MAX_PLANES]; - struct isp_surf *meta; }; #define to_isp_buffer(x) container_of((x), struct isp_buffer, vb) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 3378472fcccbdb..0e61bd1d6ee1dc 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -10,6 +10,7 @@ #include "isp-iommu.h" #include "isp-ipc.h" #include "isp-regs.h" +#include "isp-v4l2.h" #define ISP_FIRMWARE_MDELAY 1 #define ISP_FIRMWARE_MAX_TRIES 1000 diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 0475b3cf2699ee..7df434513b6c64 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -284,45 +284,3 @@ int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) return 0; } - -int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) -{ - struct isp_message *req = &chan->req, *rsp = &chan->rsp; - struct isp_buffer *tmp, *buf; - int err = 0; - - /* No need to read the whole struct */ - u64 meta_iova; - u64 *p_meta_iova = apple_isp_translate( - isp, isp->bt_surf, req->arg0 + ISP_IPC_BUFEXC_STAT_META_OFFSET, - sizeof(u64)); - - if (!p_meta_iova) { - dev_err(isp->dev, "Failed to find bufexc stat meta\n"); - return -EIO; - } - meta_iova = *p_meta_iova; - - spin_lock(&isp->buf_lock); - list_for_each_entry_safe_reverse(buf, tmp, &isp->bufs_submitted, link) { - if ((u32)buf->meta->iova == (u32)meta_iova) { - enum vb2_buffer_state state = VB2_BUF_STATE_ERROR; - - buf->vb.vb2_buf.timestamp = ktime_get_ns(); - buf->vb.sequence = isp->sequence++; - buf->vb.field = V4L2_FIELD_NONE; - if (req->arg2 == ISP_IPC_BUFEXC_FLAG_RENDER) - state = VB2_BUF_STATE_DONE; - vb2_buffer_done(&buf->vb.vb2_buf, state); - list_del(&buf->link); - break; - } - } - spin_unlock(&isp->buf_lock); - - rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; - rsp->arg1 = 0x0; - rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; - - return err; -} diff --git a/drivers/media/platform/apple/isp/isp-ipc.h b/drivers/media/platform/apple/isp/isp-ipc.h index 32d1e1bf321006..0c1d681835c72f 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.h +++ b/drivers/media/platform/apple/isp/isp-ipc.h @@ -21,6 +21,5 @@ int ipc_chan_send(struct apple_isp *isp, struct isp_channel *chan, int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan); int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan); -int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); #endif /* __ISP_IPC_H__ */ diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index cd0fb613447bfb..c76b4909c1fe4b 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -11,9 +11,9 @@ #include "isp-cam.h" #include "isp-cmd.h" -#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" +#include "isp-fw.h" #include "isp-v4l2.h" #define ISP_MIN_FRAMES 2 @@ -26,7 +26,7 @@ static bool multiplanar = false; module_param(multiplanar, bool, 0644); MODULE_PARM_DESC(multiplanar, "Enable multiplanar API"); -struct isp_h2t_buffer { +struct isp_buflist_buffer { u64 iovas[ISP_MAX_PLANES]; u32 flags[ISP_MAX_PLANES]; u32 num_planes; @@ -34,102 +34,190 @@ struct isp_h2t_buffer { u32 tag; u32 pad; } __packed; -static_assert(sizeof(struct isp_h2t_buffer) == 0x40); +static_assert(sizeof(struct isp_buflist_buffer) == 0x40); -struct isp_h2t_args { - u64 enable; +struct isp_buflist { + u64 type; u64 num_buffers; - struct isp_h2t_buffer meta; - struct isp_h2t_buffer render; -} __packed; + struct isp_buflist_buffer buffers[]; +}; + +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan) +{ + struct isp_message *req = &chan->req, *rsp = &chan->rsp; + struct isp_buffer *tmp, *buf; + struct isp_buflist *bl; + u32 count; + int err = 0; + + /* printk("H2T: 0x%llx 0x%llx 0x%llx\n", (long long)req->arg0, + (long long)req->arg1, (long long)req->arg2); */ + + if (req->arg1 < sizeof(struct isp_buflist)) { + dev_err(isp->dev, "%s: Bad length 0x%llx\n", chan->name, + req->arg1); + return -EIO; + } + + bl = apple_isp_translate(isp, isp->bt_surf, req->arg0, req->arg1); + + count = bl->num_buffers; + if (count > (req->arg1 - sizeof(struct isp_buffer)) / + sizeof(struct isp_buflist_buffer)) { + dev_err(isp->dev, "%s: Bad length 0x%llx\n", chan->name, + req->arg1); + return -EIO; + } + + spin_lock(&isp->buf_lock); + for (int i = 0; i < count; i++) { + struct isp_buflist_buffer *bufd = &bl->buffers[i]; + + /* printk("Return: 0x%llx (%d)\n", bufd->iovas[0], + bufd->pool_type); */ + + if (bufd->pool_type == 0) { + for (int j = 0; j < ARRAY_SIZE(isp->meta_surfs); j++) { + struct isp_surf *meta = isp->meta_surfs[j]; + if ((u32)bufd->iovas[0] == (u32)meta->iova) { + WARN_ON(!meta->submitted); + meta->submitted = false; + } + } + } else { + list_for_each_entry_safe_reverse( + buf, tmp, &isp->bufs_submitted, link) { + if ((u32)buf->surfs[0].iova == + (u32)bufd->iovas[0]) { + enum vb2_buffer_state state = + VB2_BUF_STATE_ERROR; + + buf->vb.vb2_buf.timestamp = + ktime_get_ns(); + buf->vb.sequence = isp->sequence++; + buf->vb.field = V4L2_FIELD_NONE; + if (req->arg2 == + ISP_IPC_BUFEXC_FLAG_RENDER) + state = VB2_BUF_STATE_DONE; + vb2_buffer_done(&buf->vb.vb2_buf, + state); + list_del(&buf->link); + } + } + } + } + spin_unlock(&isp->buf_lock); + + rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; + rsp->arg1 = 0x0; + rsp->arg2 = ISP_IPC_BUFEXC_FLAG_ACK; + + return err; +} static int isp_submit_buffers(struct apple_isp *isp) { struct isp_format *fmt = isp_get_current_format(isp); struct isp_channel *chan = isp->chan_bh; struct isp_message *req = &chan->req; - struct isp_buffer *buf, *buf2, *tmp; + struct isp_buffer *buf, *tmp; unsigned long flags; size_t offset; int err; - struct isp_h2t_args *args = - kzalloc(sizeof(struct isp_h2t_args), GFP_KERNEL); - if (!args) - return -ENOMEM; + struct isp_buflist *bl = isp->cmd_virt; + struct isp_buflist_buffer *bufd = &bl->buffers[0]; + + bl->type = 1; + bl->num_buffers = 0; spin_lock_irqsave(&isp->buf_lock, flags); + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + struct isp_surf *meta = isp->meta_surfs[i]; + + if (meta->submitted) + continue; + + /* printk("Submit: 0x%llx .. 0x%llx (meta)\n", meta->iova, + meta->iova + meta->size); */ + + bufd->num_planes = 1; + bufd->pool_type = 0; + bufd->iovas[0] = meta->iova; + bufd->flags[0] = 0x40000000; + bufd++; + bl->num_buffers++; + + meta->submitted = true; + } + while ((buf = list_first_entry_or_null(&isp->bufs_pending, struct isp_buffer, link))) { - args->meta.num_planes = 1; - args->meta.pool_type = 0; - args->meta.iovas[0] = buf->meta->iova; - args->meta.flags[0] = 0x40000000; - - args->render.num_planes = fmt->num_planes; - args->render.pool_type = isp->hw->scl1 ? - CISP_POOL_TYPE_RENDERED_SCL1 : - CISP_POOL_TYPE_RENDERED; + memset(bufd, 0, sizeof(*bufd)); + + bufd->num_planes = fmt->num_planes; + bufd->pool_type = isp->hw->scl1 ? CISP_POOL_TYPE_RENDERED_SCL1 : + CISP_POOL_TYPE_RENDERED; offset = 0; for (int j = 0; j < fmt->num_planes; j++) { - args->render.iovas[j] = buf->surfs[0].iova + offset; - args->render.flags[j] = 0x40000000; + bufd->iovas[j] = buf->surfs[0].iova + offset; + bufd->flags[j] = 0x40000000; offset += fmt->plane_size[j]; } + /* printk("Submit: 0x%llx .. 0x%llx (render)\n", + buf->surfs[0].iova, + buf->surfs[0].iova + buf->surfs[0].size); */ + bufd++; + bl->num_buffers++; + /* * Queue the buffer as submitted and release the lock for now. * We need to do this before actually submitting to avoid a * race with the buffer return codepath. */ list_move_tail(&buf->link, &isp->bufs_submitted); - spin_unlock_irqrestore(&isp->buf_lock, flags); + } + + spin_unlock_irqrestore(&isp->buf_lock, flags); + + req->arg0 = isp->cmd_iova; + req->arg1 = max_t(u64, ISP_IPC_BUFEXC_STAT_SIZE, + ((uintptr_t)bufd - (uintptr_t)bl)); + req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; + + err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); + if (err) { + /* If we fail, consider the buffer not submitted. */ + dev_err(isp->dev, + "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", + chan->name, req->arg0, req->arg1, req->arg2); + + /* + * Try to find the buffer in the list, and if it's + * still there, move it back to the pending list. + */ + spin_lock_irqsave(&isp->buf_lock, flags); - args->enable = 0x1; - args->num_buffers = 2; - - req->arg0 = isp->cmd_iova; - req->arg1 = ISP_IPC_BUFEXC_STAT_SIZE; - req->arg2 = ISP_IPC_BUFEXC_FLAG_COMMAND; - - memcpy(isp->cmd_virt, args, sizeof(*args)); - err = ipc_chan_send(isp, chan, ISP_BUFFER_TIMEOUT); - if (err) { - /* If we fail, consider the buffer not submitted. */ - dev_err(isp->dev, - "%s: failed to send bufs: [0x%llx, 0x%llx, 0x%llx]\n", - chan->name, req->arg0, req->arg1, req->arg2); - - /* - * Try to find the buffer in the list, and if it's - * still there, move it back to the pending list. - */ - spin_lock_irqsave(&isp->buf_lock, flags); + bufd = &bl->buffers[0]; + for (int i = 0; i < bl->num_buffers; i++, bufd++) { list_for_each_entry_safe_reverse( - buf2, tmp, &isp->bufs_submitted, link) { - if (buf2 == buf) { + buf, tmp, &isp->bufs_submitted, link) { + if (bufd->iovas[0] == buf->surfs[0].iova) { list_move_tail(&buf->link, &isp->bufs_pending); - spin_unlock_irqrestore(&isp->buf_lock, - flags); - return err; } } - /* - * We didn't find the buffer, which means it somehow was returned - * by the firmware even though submission failed? - */ - dev_err(isp->dev, - "buffer submission failed but buffer was returned?\n"); - spin_unlock_irqrestore(&isp->buf_lock, flags); - return err; + for (int j = 0; j < ARRAY_SIZE(isp->meta_surfs); j++) { + struct isp_surf *meta = isp->meta_surfs[j]; + if (bufd->iovas[0] == meta->iova) { + meta->submitted = false; + } + } } - spin_lock_irqsave(&isp->buf_lock, flags); + spin_unlock_irqrestore(&isp->buf_lock, flags); } - spin_unlock_irqrestore(&isp->buf_lock, flags); - - kfree(args); return err; } @@ -172,7 +260,6 @@ static void __isp_vb2_buf_cleanup(struct vb2_buffer *vb, unsigned int i) while (i--) apple_isp_iommu_unmap_sgt(isp, &buf->surfs[i]); - isp_free_surface(isp, buf->meta); } static void isp_vb2_buf_cleanup(struct vb2_buffer *vb) @@ -188,10 +275,6 @@ static int isp_vb2_buf_init(struct vb2_buffer *vb) unsigned int i; int err; - buf->meta = isp_alloc_surface(isp, isp->hw->meta_size); - if (!buf->meta) - return -ENOMEM; - for (i = 0; i < vb->num_planes; i++) { struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, i); err = apple_isp_iommu_map_sgt(isp, &buf->surfs[i], sgt, @@ -678,6 +761,16 @@ int apple_isp_setup_video(struct apple_isp *isp) return err; } + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + isp->meta_surfs[i] = + isp_alloc_surface_vmap(isp, isp->hw->meta_size); + if (!isp->meta_surfs[i]) { + isp_err(isp, "failed to alloc meta surface\n"); + err = -ENOMEM; + goto surf_cleanup; + } + } + media_device_init(&isp->mdev); isp->v4l2_dev.mdev = &isp->mdev; isp->mdev.ops = &isp_media_device_ops; @@ -744,6 +837,13 @@ int apple_isp_setup_video(struct apple_isp *isp) media_device_unregister(&isp->mdev); media_cleanup: media_device_cleanup(&isp->mdev); +surf_cleanup: + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + if (isp->meta_surfs[i]) + isp_free_surface(isp, isp->meta_surfs[i]); + isp->meta_surfs[i] = NULL; + } + return err; } @@ -753,4 +853,9 @@ void apple_isp_remove_video(struct apple_isp *isp) v4l2_device_unregister(&isp->v4l2_dev); media_device_unregister(&isp->mdev); media_device_cleanup(&isp->mdev); + for (int i = 0; i < ARRAY_SIZE(isp->meta_surfs); i++) { + if (isp->meta_surfs[i]) + isp_free_surface(isp, isp->meta_surfs[i]); + isp->meta_surfs[i] = NULL; + } } diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h index df9b961d77bc17..e81e4de6ca641f 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.h +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -8,5 +8,6 @@ int apple_isp_setup_video(struct apple_isp *isp); void apple_isp_remove_video(struct apple_isp *isp); +int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); #endif /* __ISP_V4L2_H__ */ From 747e937e4967e11efadaa4fd0a958edb0c4239c3 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:25:07 +0900 Subject: [PATCH 41/60] media: apple: isp: Clear IRQs when resetting coproc XXX this might be wrong on some chips? Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 0e61bd1d6ee1dc..4b963f2a35d320 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -213,6 +213,7 @@ static int isp_reset_coproc(struct apple_isp *isp) { int retries; u32 status; + u32 val; isp_coproc_write32(isp, ISP_COPROC_EDPRCR, 0x2); @@ -228,6 +229,18 @@ static int isp_reset_coproc(struct apple_isp *isp) isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_4, 0xffffffff); isp_coproc_write32(isp, ISP_COPROC_IRQ_MASK_5, 0xffffffff); + for (retries = 0; retries < 128; retries++) { + val = isp_coproc_read32(isp, 0x818); + if (val == 0) + break; + } + + for (retries = 0; retries < 128; retries++) { + val = isp_coproc_read32(isp, 0x81c); + if (val == 0) + break; + } + for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { status = isp_coproc_read32(isp, ISP_COPROC_STATUS); if (status & ISP_COPROC_IN_WFI) { From 3b680125dab4920e2873dd2f7f5291c687a50d74 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:25:50 +0900 Subject: [PATCH 42/60] media: apple: isp: Add a missing read barrier (possibly?) Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-ipc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 7df434513b6c64..9d965ef7756b9b 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -157,6 +157,8 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) static inline bool chan_tx_done(struct apple_isp *isp, struct isp_channel *chan) { + dma_rmb(); + chan_read_msg(isp, chan, &chan->rsp); if ((chan->rsp.arg0) == (chan->req.arg0 | ISP_IPC_FLAG_ACK)) { chan_update_cursor(chan); From a9a2f69d50409adf64fcf411585006d9a6308ff7 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:26:47 +0900 Subject: [PATCH 43/60] media: apple: isp: VMap only what is necessary, remove redundant logging state bit Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-ipc.c | 41 ++++++++-------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 9d965ef7756b9b..54a88ed876c2b7 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -204,7 +204,7 @@ int ipc_tm_handle(struct apple_isp *isp, struct isp_channel *chan) dma_addr_t iova = req->arg0 & ~ISP_IPC_FLAG_TERMINAL_ACK; u32 size = req->arg1; if (iova && size && size < sizeof(buf) && - test_bit(ISP_STATE_LOGGING, &isp->state)) { + isp->log_surf) { void *p = apple_isp_translate(isp, isp->log_surf, iova, size); if (p) { size = min_t(u32, size, 512); @@ -243,42 +243,31 @@ int ipc_sm_handle(struct apple_isp *isp, struct isp_channel *chan) rsp->arg1 = 0x0; rsp->arg2 = 0x0; /* macOS uses this to index surfaces */ + switch (surf->type) { + case 0x4c4f47: /* "LOG" */ + isp->log_surf = surf; + break; + case 0x4d495343: /* "MISC" */ + /* Hacky... maybe there's a better way to identify this surface? */ + if (surf->size == 0xc000) + isp->bt_surf = surf; + break; + default: + // skip vmap + return 0; + } + err = isp_surf_vmap(isp, surf); if (err < 0) { isp_err(isp, "failed to vmap iova=0x%llx size=0x%llx\n", surf->iova, surf->size); - } else { - switch (surf->type) { - case 0x4c4f47: /* "LOG" */ - isp->log_surf = surf; - break; - case 0x4d495343: /* "MISC" */ - /* Hacky... maybe there's a better way to identify this surface? */ - if (surf->size == 0xc000) - isp->bt_surf = surf; - break; - } } - -#ifdef APPLE_ISP_DEBUG - /* Only enabled in debug builds so it shouldn't matter, but - * the LOG surface is always the first surface requested. - */ - if (!test_bit(ISP_STATE_LOGGING, &isp->state)) - set_bit(ISP_STATE_LOGGING, &isp->state); -#endif - /* To the gc it goes... */ - } else { /* This should be the shared surface free request, but * 1) The fw doesn't request to free all of what it requested * 2) The fw continues to access the surface after * So we link it to the gc, which runs after fw shutdown */ -#ifdef APPLE_ISP_DEBUG - if (test_bit(ISP_STATE_LOGGING, &isp->state)) - clear_bit(ISP_STATE_LOGGING, &isp->state); -#endif rsp->arg0 = req->arg0 | ISP_IPC_FLAG_ACK; rsp->arg1 = 0x0; rsp->arg2 = 0x0; From c06932c7c2ba4e9e5e2a834801e773c286f301c9 Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:28:03 +0900 Subject: [PATCH 44/60] media: apple: isp: Only reset coproc when necessary, fix minor race Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 4b963f2a35d320..a4495ccbe89545 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -268,16 +268,22 @@ static void isp_firmware_shutdown_stage1(struct apple_isp *isp) static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; + u32 val; + err = apple_isp_power_up_domains(isp); if (err < 0) return err; - err = isp_reset_coproc(isp); - if (err < 0) - return err; isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); + val = isp_gpio_read32(isp, ISP_GPIO_1); + if (val == 0xfeedbabe) { + err = isp_reset_coproc(isp); + if (err < 0) + return err; + } + isp_gpio_write32(isp, ISP_GPIO_0, 0x0); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); isp_gpio_write32(isp, ISP_GPIO_2, 0x0); @@ -293,7 +299,6 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_coproc_write32(isp, ISP_COPROC_CONTROL, 0x10); /* Wait for ISP_GPIO_7 to 0x0 -> 0x8042006 */ - isp_gpio_write32(isp, ISP_GPIO_7, 0x0); for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { u32 val = isp_gpio_read32(isp, ISP_GPIO_7); if (val == 0x8042006) { From afb348f30588e767a712a555e2c3600f005e09bc Mon Sep 17 00:00:00 2001 From: Asahi Lina Date: Wed, 4 Oct 2023 22:28:55 +0900 Subject: [PATCH 45/60] media: apple: isp: Option to use CMD_STOP (ifdeffed out) Signed-off-by: Asahi Lina --- drivers/media/platform/apple/isp/isp-fw.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index a4495ccbe89545..78521d83535087 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -593,11 +593,26 @@ static int isp_stop_command_processor(struct apple_isp *isp) { int retries; +#if 0 + int res = isp_cmd_stop(isp, 0); + if (res) { + isp_err(isp, "isp_cmd_stop() failed\n"); + return res; + } + /* Wait for ISP_GPIO_0 to 0xf7fbdff9 -> 0x8042006 */ isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); - /* Their CISP_CMD_STOP implementation is buggy */ - isp_cmd_suspend(isp); + isp_cmd_power_down(isp); +#else + isp_gpio_write32(isp, ISP_GPIO_0, 0xf7fbdff9); + + int res = isp_cmd_suspend(isp); + if (res) { + isp_err(isp, "isp_cmd_suspend() failed\n"); + return res; + } +#endif for (retries = 0; retries < ISP_FIRMWARE_MAX_TRIES; retries++) { u32 val = isp_gpio_read32(isp, ISP_GPIO_0); From cf038045626e2bf29ade3b575e03fe82020b9473 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 5 Oct 2023 23:24:32 +0900 Subject: [PATCH 46/60] media: apple: isp: Use a more user-friendly device name Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 31c527532aebac..847e0a90975fb5 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -16,6 +16,7 @@ /* #define APPLE_ISP_DEBUG */ #define APPLE_ISP_DEVICE_NAME "apple-isp" +#define APPLE_ISP_CARD_NAME "FaceTime HD Camera" #define ISP_MAX_CHANNELS 6 #define ISP_IPC_MESSAGE_SIZE 64 diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index c76b4909c1fe4b..46d9c372a9e312 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -448,7 +448,7 @@ struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, static int isp_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strscpy(cap->card, APPLE_ISP_DEVICE_NAME, sizeof(cap->card)); + strscpy(cap->card, APPLE_ISP_CARD_NAME, sizeof(cap->card)); strscpy(cap->driver, APPLE_ISP_DEVICE_NAME, sizeof(cap->driver)); return 0; From fb6d5d6e94b2e12dedc4608a6c8dc4dbccc4a581 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Fri, 6 Oct 2023 21:34:11 +0200 Subject: [PATCH 47/60] media: apple: isp: Parse firmware version from device tree Required since t8112-isp uses a 32-bit address in the CISP_CMD_CH_SET_FILE_LOAD command with the macOS 12.4 firmware. Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-cmd.c | 3 +- drivers/media/platform/apple/isp/isp-drv.c | 71 ++++++++++++++++++++++ drivers/media/platform/apple/isp/isp-drv.h | 8 +++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cmd.c b/drivers/media/platform/apple/isp/isp-cmd.c index 9c5808b4e831be..ee491d2cb42c5b 100644 --- a/drivers/media/platform/apple/isp/isp-cmd.c +++ b/drivers/media/platform/apple/isp/isp-cmd.c @@ -2,6 +2,7 @@ /* Copyright 2023 Eileen Yoon */ #include "isp-cmd.h" +#include "isp-drv.h" #include "isp-iommu.h" #include "isp-ipc.h" @@ -261,7 +262,7 @@ int isp_cmd_ch_buffer_return(struct apple_isp *isp, u32 chan) int isp_cmd_ch_set_file_load(struct apple_isp *isp, u32 chan, u64 addr, u32 size) { - if (isp->hw->gen >= ISP_GEN_T8112) { + if (isp->fw_compat >= ISP_FIRMWARE_V_13_5) { struct cmd_ch_set_file_load64 args = { .opcode = CISP_OPCODE(CISP_CMD_CH_SET_FILE_LOAD), .chan = chan, diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 45597e0361fa8a..7a49b4e62a7f7a 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -224,6 +224,72 @@ static int apple_isp_init_presets(struct apple_isp *isp) return err; } +static const char * isp_fw2str(enum isp_firmware_version version) +{ + switch (version) { + case ISP_FIRMWARE_V_12_3: + return "12.3"; + case ISP_FIRMWARE_V_12_4: + return "12.4"; + case ISP_FIRMWARE_V_13_5: + return "13.5"; + default: + return "unknown"; + } +} + +#define ISP_FW_VERSION_MIN_LEN 3 +#define ISP_FW_VERSION_MAX_LEN 5 + +static enum isp_firmware_version isp_read_fw_version(struct device *dev, + const char *name) +{ + u32 ver[ISP_FW_VERSION_MAX_LEN]; + int len = of_property_read_variable_u32_array(dev->of_node, name, ver, + ISP_FW_VERSION_MIN_LEN, + ISP_FW_VERSION_MAX_LEN); + + switch (len) { + case 3: + if (ver[0] == 12 && ver[1] == 3 && ver[2] <= 1) + return ISP_FIRMWARE_V_12_3; + else if (ver[0] == 12 && ver[1] == 4 && ver[2] == 0) + return ISP_FIRMWARE_V_12_4; + else if (ver[0] == 13 && ver[1] == 5 && ver[2] == 0) + return ISP_FIRMWARE_V_13_5; + + dev_warn(dev, "unknown %s: %d.%d.%d\n", name, ver[0], ver[1], ver[2]); + break; + case 4: + dev_warn(dev, "unknown %s: %d.%d.%d.%d\n", name, ver[0], ver[1], + ver[2], ver[3]); + break; + case 5: + dev_warn(dev, "unknown %s: %d.%d.%d.%d.%d\n", name, ver[0], + ver[1], ver[2], ver[3], ver[4]); + break; + default: + dev_warn(dev, "could not parse %s: %d\n", name, len); + break; + } + + return ISP_FIRMWARE_V_UNKNOWN; +} + +static enum isp_firmware_version isp_check_firmware_version(struct device *dev) +{ + enum isp_firmware_version version, compat; + + /* firmware version is just informative */ + version = isp_read_fw_version(dev, "apple,firmware-version"); + compat = isp_read_fw_version(dev, "apple,firmware-compat"); + + dev_info(dev, "ISP firmware-compat: %s (FW: %s)\n", isp_fw2str(compat), + isp_fw2str(version)); + + return compat; +} + static int apple_isp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -243,6 +309,11 @@ static int apple_isp_probe(struct platform_device *pdev) platform_set_drvdata(pdev, isp); dev_set_drvdata(dev, isp); + /* Differences between firmware versions are rather minor so try to work + * with unknown firmware. + */ + isp->fw_compat = isp_check_firmware_version(dev); + err = of_property_read_u32(dev->of_node, "apple,platform-id", &isp->platform_id); if (err) { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 847e0a90975fb5..2ccd3524be65b8 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -32,6 +32,13 @@ enum isp_generation { ISP_GEN_T8112, }; +enum isp_firmware_version { + ISP_FIRMWARE_V_UNKNOWN, + ISP_FIRMWARE_V_12_3, + ISP_FIRMWARE_V_12_4, + ISP_FIRMWARE_V_13_5, +}; + struct isp_surf { struct drm_mm_node *mm; struct list_head head; @@ -180,6 +187,7 @@ struct isp_format { struct apple_isp { struct device *dev; const struct apple_isp_hw *hw; + enum isp_firmware_version fw_compat; u32 platform_id; u32 temporal_filter; struct isp_preset *presets; From ab67cb8ec6d8079aaa7f333c4878617a341df601 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 8 Oct 2023 18:02:12 +0900 Subject: [PATCH 48/60] media: apple: isp: Show camera presets even for unsupported sensors This makes adding support easier. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-cam.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 69b67df5697501..bbc298d8375e16 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -212,6 +212,10 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) print_hex_dump(KERN_INFO, "apple-isp: ch: ", DUMP_PREFIX_NONE, 32, 4, args, sizeof(*args), false); + for (u32 ps = 0; ps < args->num_presets; ps++) { + isp_ch_get_camera_preset(isp, ch, ps); + } + err = isp_ch_get_sensor_id(isp, ch); if (err || (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { @@ -221,10 +225,6 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) return -ENODEV; } - for (u32 ps = 0; ps < args->num_presets; ps++) { - isp_ch_get_camera_preset(isp, ch, ps); - } - exit: kfree(args); From c27abc0e2d4c8435c3722506e575203f3292d039 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 8 Oct 2023 18:03:20 +0900 Subject: [PATCH 49/60] media: apple: isp: Enable IMX364 sensor This is used on j45[67]. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-cam.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index bbc298d8375e16..662fc045941381 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -218,7 +218,8 @@ static int isp_ch_cache_sensor_info(struct apple_isp *isp, u32 ch) err = isp_ch_get_sensor_id(isp, ch); if (err || - (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01)) { + (fmt->id != ISP_IMX248_1820_01 && fmt->id != ISP_IMX558_1921_01 && + fmt->id != ISP_IMX364_8720_01)) { dev_err(isp->dev, "ch %d: unsupported sensor. Please file a bug report with hardware info & dmesg trace.\n", ch); From ba2590eba25b625ceccf88e8a7f50d35ebe59465 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 12 Oct 2023 02:41:08 +0900 Subject: [PATCH 50/60] media: apple: isp: implement ENUM_FRAMEINTERVALS trivially Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-v4l2.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 46d9c372a9e312..df636f47f0bbe9 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -497,6 +497,18 @@ static int isp_vidioc_enum_framesizes(struct file *file, void *fh, return 0; } +static int isp_vidioc_enum_frameintervals(struct file *filp, void *priv, + struct v4l2_frmivalenum *interval) +{ + if (interval->index != 0) + return -EINVAL; + + interval->type = V4L2_FRMIVAL_TYPE_DISCRETE; + interval->discrete.numerator = 1; + interval->discrete.denominator = 30; + return 0; +} + static inline void isp_get_sp_pix_format(struct apple_isp *isp, struct v4l2_format *f, struct isp_format *fmt) @@ -717,6 +729,7 @@ static const struct v4l2_ioctl_ops isp_v4l2_ioctl_ops = { .vidioc_try_fmt_vid_cap_mplane = isp_vidioc_try_format_mplane, .vidioc_enum_framesizes = isp_vidioc_enum_framesizes, + .vidioc_enum_frameintervals = isp_vidioc_enum_frameintervals, .vidioc_enum_input = isp_vidioc_enum_input, .vidioc_g_input = isp_vidioc_get_input, .vidioc_s_input = isp_vidioc_set_input, From 41283459cc93935c30e2cb1dd792f6b5ea7c7459 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Fri, 3 Nov 2023 20:49:38 +0900 Subject: [PATCH 51/60] media: apple: isp: Use a mutex instead of a spinlock for channels Fixes lockdep splats because we do surface stuff with this held, which takes a mutex. Signed-off-by: Hector Martin --- drivers/media/platform/apple/isp/isp-drv.h | 2 +- drivers/media/platform/apple/isp/isp-fw.c | 2 +- drivers/media/platform/apple/isp/isp-ipc.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 2ccd3524be65b8..4bdf7616e0efe4 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -76,7 +76,7 @@ struct isp_channel { void *virt; u32 doorbell; u32 cursor; - spinlock_t lock; + struct mutex lock; struct isp_message req; struct isp_message rsp; const struct isp_chan_ops *ops; diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 78521d83535087..c0bda6cb005633 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -491,7 +491,7 @@ static int isp_fill_channel_info(struct apple_isp *isp) chan->virt = apple_isp_ipc_translate(isp, desc.iova, chan->size); chan->cursor = 0; - spin_lock_init(&chan->lock); + mutex_init(&chan->lock); if (!chan->virt) { dev_err(isp->dev, "Failed to find channel buffer\n"); diff --git a/drivers/media/platform/apple/isp/isp-ipc.c b/drivers/media/platform/apple/isp/isp-ipc.c index 54a88ed876c2b7..7300eb60892116 100644 --- a/drivers/media/platform/apple/isp/isp-ipc.c +++ b/drivers/media/platform/apple/isp/isp-ipc.c @@ -138,7 +138,7 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) { int err = 0; - spin_lock(&chan->lock); + mutex_lock(&chan->lock); while (1) { chan_read_msg(isp, chan, &chan->req); if (chan_rx_done(isp, chan)) { @@ -150,7 +150,7 @@ int ipc_chan_handle(struct apple_isp *isp, struct isp_channel *chan) break; } } - spin_unlock(&chan->lock); + mutex_unlock(&chan->lock); return err; } From a865fc5979b10ce15ffdadf313579e1d41ac159b Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Fri, 13 Oct 2023 21:09:43 +0900 Subject: [PATCH 52/60] media: apple: isp: Support system sleep Signed-off-by: Eileen Yoon --- drivers/media/platform/apple/isp/isp-drv.c | 29 +++++++++++- drivers/media/platform/apple/isp/isp-drv.h | 1 + drivers/media/platform/apple/isp/isp-fw.c | 7 +++ drivers/media/platform/apple/isp/isp-v4l2.c | 50 ++++++++++++++++++--- drivers/media/platform/apple/isp/isp-v4l2.h | 3 ++ 5 files changed, 81 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-drv.c b/drivers/media/platform/apple/isp/isp-drv.c index 7a49b4e62a7f7a..6034761ce7d8fd 100644 --- a/drivers/media/platform/apple/isp/isp-drv.c +++ b/drivers/media/platform/apple/isp/isp-drv.c @@ -551,17 +551,42 @@ static const struct of_device_id apple_isp_of_match[] = { }; MODULE_DEVICE_TABLE(of, apple_isp_of_match); +static __maybe_unused int apple_isp_runtime_suspend(struct device *dev) +{ + /* RPM sleep is called when the V4L2 file handle is closed */ + return 0; +} + +static __maybe_unused int apple_isp_runtime_resume(struct device *dev) +{ + return 0; +} + static __maybe_unused int apple_isp_suspend(struct device *dev) { + struct apple_isp *isp = dev_get_drvdata(dev); + + /* We must restore V4L2 context on system resume. If we were streaming + * before, we (essentially) stop streaming and start streaming again. + */ + apple_isp_video_suspend(isp); + return 0; } static __maybe_unused int apple_isp_resume(struct device *dev) { + struct apple_isp *isp = dev_get_drvdata(dev); + + apple_isp_video_resume(isp); + return 0; } -DEFINE_RUNTIME_DEV_PM_OPS(apple_isp_pm_ops, apple_isp_suspend, apple_isp_resume, - NULL); + +static const struct dev_pm_ops apple_isp_pm_ops = { + SYSTEM_SLEEP_PM_OPS(apple_isp_suspend, apple_isp_resume) + RUNTIME_PM_OPS(apple_isp_runtime_suspend, apple_isp_runtime_resume, NULL) +}; static struct platform_driver apple_isp_driver = { .driver = { diff --git a/drivers/media/platform/apple/isp/isp-drv.h b/drivers/media/platform/apple/isp/isp-drv.h index 4bdf7616e0efe4..96a1d0b39f860d 100644 --- a/drivers/media/platform/apple/isp/isp-drv.h +++ b/drivers/media/platform/apple/isp/isp-drv.h @@ -270,6 +270,7 @@ struct isp_buffer { enum { ISP_STATE_STREAMING, ISP_STATE_LOGGING, + ISP_STATE_SLEEPING, }; #ifdef APPLE_ISP_DEBUG diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index c0bda6cb005633..5d7615d0728b47 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -277,12 +277,19 @@ static int isp_firmware_boot_stage1(struct apple_isp *isp) isp_gpio_write32(isp, ISP_GPIO_CLOCK_EN, 0x1); +#if 0 + /* This doesn't work well with system sleep */ val = isp_gpio_read32(isp, ISP_GPIO_1); if (val == 0xfeedbabe) { err = isp_reset_coproc(isp); if (err < 0) return err; } +#endif + + err = isp_reset_coproc(isp); + if (err < 0) + return err; isp_gpio_write32(isp, ISP_GPIO_0, 0x0); isp_gpio_write32(isp, ISP_GPIO_1, 0x0); diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index df636f47f0bbe9..1044ba62367cb4 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -337,13 +337,10 @@ static void isp_vb2_buf_queue(struct vb2_buffer *vb) isp_submit_buffers(isp); } -static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +static int apple_isp_start_streaming(struct apple_isp *isp) { - struct apple_isp *isp = vb2_get_drv_priv(q); int err; - isp->sequence = 0; - err = apple_isp_start_camera(isp); if (err) { dev_err(isp->dev, "failed to start camera: %d\n", err); @@ -373,16 +370,55 @@ static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) return err; } -static void isp_vb2_stop_streaming(struct vb2_queue *q) +static void apple_isp_stop_streaming(struct apple_isp *isp) { - struct apple_isp *isp = vb2_get_drv_priv(q); - clear_bit(ISP_STATE_STREAMING, &isp->state); apple_isp_stop_capture(isp); apple_isp_stop_camera(isp); +} + +static int isp_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + isp->sequence = 0; + + return apple_isp_start_streaming(isp); +} + +static void isp_vb2_stop_streaming(struct vb2_queue *q) +{ + struct apple_isp *isp = vb2_get_drv_priv(q); + + apple_isp_stop_streaming(isp); isp_vb2_release_buffers(isp, VB2_BUF_STATE_ERROR); } +int apple_isp_video_suspend(struct apple_isp *isp) +{ + /* Swap into STATE_SLEEPING as isp_vb2_buf_queue() submits on + * STATE_STREAMING. + */ + if (test_bit(ISP_STATE_STREAMING, &isp->state)) { + /* Signal buffers to be recycled for clean shutdown */ + isp_vb2_release_buffers(isp, VB2_BUF_STATE_QUEUED); + apple_isp_stop_streaming(isp); + set_bit(ISP_STATE_SLEEPING, &isp->state); + } + + return 0; +} + +int apple_isp_video_resume(struct apple_isp *isp) +{ + if (test_bit(ISP_STATE_SLEEPING, &isp->state)) { + clear_bit(ISP_STATE_SLEEPING, &isp->state); + apple_isp_start_streaming(isp); + } + + return 0; +} + static const struct vb2_ops isp_vb2_ops = { .queue_setup = isp_vb2_queue_setup, .buf_init = isp_vb2_buf_init, diff --git a/drivers/media/platform/apple/isp/isp-v4l2.h b/drivers/media/platform/apple/isp/isp-v4l2.h index e81e4de6ca641f..4d47deeb83b055 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.h +++ b/drivers/media/platform/apple/isp/isp-v4l2.h @@ -10,4 +10,7 @@ int apple_isp_setup_video(struct apple_isp *isp); void apple_isp_remove_video(struct apple_isp *isp); int ipc_bt_handle(struct apple_isp *isp, struct isp_channel *chan); +int apple_isp_video_suspend(struct apple_isp *isp); +int apple_isp_video_resume(struct apple_isp *isp); + #endif /* __ISP_V4L2_H__ */ From 98115f7be261cce609f3c9e7c0ec5a6db150d24c Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 19 Nov 2023 16:01:31 +0900 Subject: [PATCH 53/60] fixup! media: apple: isp: Minor changes to cam flow --- drivers/media/platform/apple/isp/isp-cam.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-cam.c b/drivers/media/platform/apple/isp/isp-cam.c index 662fc045941381..c889173bd348f3 100644 --- a/drivers/media/platform/apple/isp/isp-cam.c +++ b/drivers/media/platform/apple/isp/isp-cam.c @@ -404,18 +404,6 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); - if (err) - return err; - - err = isp_cmd_apple_ch_motion_history_start(isp, ch); - if (err) - return err; - - err = isp_cmd_apple_ch_temporal_filter_enable(isp, ch); - if (err) - return err; - err = isp_cmd_apple_ch_ae_fd_scene_metering_config_set(isp, ch); if (err) return err; @@ -444,7 +432,7 @@ static int isp_ch_configure_capture(struct apple_isp *isp, u32 ch) if (err) return err; - err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->hw->temporal_filter); + err = isp_cmd_apple_ch_temporal_filter_start(isp, ch, isp->temporal_filter); if (err) return err; From 1662cac81e45d41ba6aee5af85f431247a139685 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 27 Feb 2024 19:21:04 +0100 Subject: [PATCH 54/60] fixup! media: apple: Add Apple ISP driver --- drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index 1044ba62367cb4..feb2623fb2fdcb 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -849,7 +849,7 @@ int apple_isp_setup_video(struct apple_isp *isp) vbq->mem_ops = &vb2_dma_sg_memops; vbq->buf_struct_size = sizeof(struct isp_buffer); vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - vbq->min_buffers_needed = ISP_MIN_FRAMES; + vbq->min_queued_buffers = ISP_MIN_FRAMES; vbq->lock = &isp->video_lock; err = vb2_queue_init(vbq); From ace7bb4ba5991bf4179cb1450bff1dc81616addf Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:11 +0100 Subject: [PATCH 55/60] fixup! media: apple: isp: Remove ioread/iowrite and stop doing raw address translation --- drivers/media/platform/apple/isp/isp-fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 5d7615d0728b47..825f0b598d91ee 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -3,6 +3,7 @@ #include "isp-fw.h" +#include #include #include From 413dc7e4ec7dac667f3e4c42dc14aa9a0f03c6f9 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:11 +0100 Subject: [PATCH 56/60] fixup! media: apple: isp: Make sub-pmdomain handling explicit --- drivers/media/platform/apple/isp/isp-fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 825f0b598d91ee..0248c80baec771 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -42,7 +42,7 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) } int apple_isp_power_up_domains(struct apple_isp *isp) -{ +static int apple_isp_power_up_domains(struct apple_isp *isp) int ret; if (isp->pds_active) From b6aeeaff527bf99d350721be80ab512acfe2fde1 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:11 +0100 Subject: [PATCH 57/60] fixup! media: apple: isp: Make sub-pmdomain handling explicit --- drivers/media/platform/apple/isp/isp-fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 0248c80baec771..da8419b9446e54 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -65,7 +65,7 @@ static int apple_isp_power_up_domains(struct apple_isp *isp) } void apple_isp_power_down_domains(struct apple_isp *isp) -{ +static void apple_isp_power_down_domains(struct apple_isp *isp) int ret; if (!isp->pds_active) From 818bb46880e9f666a423783fd5b271661d29ddf3 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:11 +0100 Subject: [PATCH 58/60] fixup! media: apple: isp: Working t602x and multiple formats and more fixes --- drivers/media/platform/apple/isp/isp-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/apple/isp/isp-v4l2.c b/drivers/media/platform/apple/isp/isp-v4l2.c index feb2623fb2fdcb..0561653ea7becd 100644 --- a/drivers/media/platform/apple/isp/isp-v4l2.c +++ b/drivers/media/platform/apple/isp/isp-v4l2.c @@ -455,7 +455,7 @@ static int isp_set_preset(struct apple_isp *isp, struct isp_format *fmt, return 0; } -struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, +static struct isp_preset *isp_select_preset(struct apple_isp *isp, u32 width, u32 height) { struct isp_preset *preset, *best = &isp->presets[0]; From 8e6fc40a7b8ab241c601a218966e862145ff939e Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:11 +0100 Subject: [PATCH 59/60] fixup! media: apple: Add Apple ISP driver --- drivers/media/platform/apple/isp/isp-fw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index da8419b9446e54..2a4bea1668a613 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "isp-cmd.h" #include "isp-iommu.h" From 6666387ff5c7bedfd35e6740716eadb77fffc35c Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 5 Mar 2024 21:16:39 +0100 Subject: [PATCH 60/60] fixup! media: apple: isp: Support system sleep Signed-off-by: Janne Grunau --- drivers/media/platform/apple/isp/isp-fw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/apple/isp/isp-fw.c b/drivers/media/platform/apple/isp/isp-fw.c index 2a4bea1668a613..a39f5fb4445fa7 100644 --- a/drivers/media/platform/apple/isp/isp-fw.c +++ b/drivers/media/platform/apple/isp/isp-fw.c @@ -42,8 +42,8 @@ static inline void isp_gpio_write32(struct apple_isp *isp, u32 reg, u32 val) writel(val, isp->gpio + reg); } -int apple_isp_power_up_domains(struct apple_isp *isp) static int apple_isp_power_up_domains(struct apple_isp *isp) +{ int ret; if (isp->pds_active) @@ -65,8 +65,8 @@ static int apple_isp_power_up_domains(struct apple_isp *isp) return 0; } -void apple_isp_power_down_domains(struct apple_isp *isp) static void apple_isp_power_down_domains(struct apple_isp *isp) +{ int ret; if (!isp->pds_active) @@ -270,7 +270,7 @@ static void isp_firmware_shutdown_stage1(struct apple_isp *isp) static int isp_firmware_boot_stage1(struct apple_isp *isp) { int err, retries; - u32 val; + // u32 val; err = apple_isp_power_up_domains(isp); if (err < 0)