Lines Matching +full:t8103 +full:- +full:dart
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Apple DART (Device Address Resolution Table) IOMMU driver
7 * Based on arm/arm-smmu/arm-ssmu.c and arm/arm-smmu-v3/arm-smmu-v3.c
10 * and on exynos-iommu.c
18 #include <linux/dma-mapping.h>
21 #include <linux/io-pgtable.h>
35 #include "dma-iommu.h"
144 #define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2)) argument
146 #define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \ argument
147 (((dart)->hw->ttbr_count * (sid)) << 2) + \
188 * Private structure associated with each DART device.
191 * @hw: SoC-specific hardware data
194 * @clks: clocks associated with this DART
196 * @lock: lock for hardware operations involving this dart
197 * @pgsize: pagesize supported by this DART
198 * @supports_bypass: indicates if this DART supports bypass mode
238 * and never changed again afterwards. Devices with different dart pointers
241 * @dart dart pointer
245 struct apple_dart *dart; member
249 struct apple_dart *dart; member
254 * This structure is attached to each iommu domain handled by a DART.
256 * @pgtbl_ops: pagetable ops allocated by io-pgtable
293 for (i = 0, stream_map = &(base)->stream_maps[0]; \
294 i < MAX_DARTS_PER_DEVICE && stream_map->dart; \
295 stream_map = &(base)->stream_maps[++i])
308 struct apple_dart *dart = stream_map->dart; in apple_dart_hw_enable_translation() local
311 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) in apple_dart_hw_enable_translation()
312 writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid)); in apple_dart_hw_enable_translation()
317 struct apple_dart *dart = stream_map->dart; in apple_dart_hw_disable_dma() local
320 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) in apple_dart_hw_disable_dma()
321 writel(dart->hw->tcr_disabled, dart->regs + DART_TCR(dart, sid)); in apple_dart_hw_disable_dma()
327 struct apple_dart *dart = stream_map->dart; in apple_dart_hw_enable_bypass() local
330 WARN_ON(!stream_map->dart->supports_bypass); in apple_dart_hw_enable_bypass()
331 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) in apple_dart_hw_enable_bypass()
332 writel(dart->hw->tcr_bypass, in apple_dart_hw_enable_bypass()
333 dart->regs + DART_TCR(dart, sid)); in apple_dart_hw_enable_bypass()
339 struct apple_dart *dart = stream_map->dart; in apple_dart_hw_set_ttbr() local
342 WARN_ON(paddr & ((1 << dart->hw->ttbr_shift) - 1)); in apple_dart_hw_set_ttbr()
343 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) in apple_dart_hw_set_ttbr()
344 writel(dart->hw->ttbr_valid | in apple_dart_hw_set_ttbr()
345 (paddr >> dart->hw->ttbr_shift) << dart->hw->ttbr_addr_field_shift, in apple_dart_hw_set_ttbr()
346 dart->regs + DART_TTBR(dart, sid, idx)); in apple_dart_hw_set_ttbr()
352 struct apple_dart *dart = stream_map->dart; in apple_dart_hw_clear_ttbr() local
355 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) in apple_dart_hw_clear_ttbr()
356 writel(0, dart->regs + DART_TTBR(dart, sid, idx)); in apple_dart_hw_clear_ttbr()
364 for (i = 0; i < stream_map->dart->hw->ttbr_count; ++i) in apple_dart_hw_clear_all_ttbrs()
376 spin_lock_irqsave(&stream_map->dart->lock, flags); in apple_dart_t8020_hw_stream_command()
378 writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT); in apple_dart_t8020_hw_stream_command()
379 writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND); in apple_dart_t8020_hw_stream_command()
382 stream_map->dart->regs + DART_T8020_STREAM_COMMAND, command_reg, in apple_dart_t8020_hw_stream_command()
386 spin_unlock_irqrestore(&stream_map->dart->lock, flags); in apple_dart_t8020_hw_stream_command()
389 dev_err(stream_map->dart->dev, in apple_dart_t8020_hw_stream_command()
391 command, stream_map->sidmap[0]); in apple_dart_t8020_hw_stream_command()
402 struct apple_dart *dart = stream_map->dart; in apple_dart_t8110_hw_tlb_command() local
407 spin_lock_irqsave(&dart->lock, flags); in apple_dart_t8110_hw_tlb_command()
409 for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) { in apple_dart_t8110_hw_tlb_command()
412 writel(val, dart->regs + DART_T8110_TLB_CMD); in apple_dart_t8110_hw_tlb_command()
415 dart->regs + DART_T8110_TLB_CMD, val, in apple_dart_t8110_hw_tlb_command()
424 spin_unlock_irqrestore(&dart->lock, flags); in apple_dart_t8110_hw_tlb_command()
427 dev_err(stream_map->dart->dev, in apple_dart_t8110_hw_tlb_command()
450 static int apple_dart_hw_reset(struct apple_dart *dart) in apple_dart_hw_reset() argument
456 config = readl(dart->regs + dart->hw->lock); in apple_dart_hw_reset()
457 if (config & dart->hw->lock_bit) { in apple_dart_hw_reset()
458 dev_err(dart->dev, "DART is locked down until reboot: %08x\n", in apple_dart_hw_reset()
460 return -EINVAL; in apple_dart_hw_reset()
463 stream_map.dart = dart; in apple_dart_hw_reset()
465 bitmap_set(stream_map.sidmap, 0, dart->num_streams); in apple_dart_hw_reset()
470 for (i = 0; i < BITS_TO_U32(dart->num_streams); i++) in apple_dart_hw_reset()
471 writel(U32_MAX, dart->regs + dart->hw->enable_streams + 4 * i); in apple_dart_hw_reset()
474 writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error); in apple_dart_hw_reset()
476 if (dart->hw->type == DART_T8110) in apple_dart_hw_reset()
477 writel(0, dart->regs + DART_T8110_ERROR_MASK); in apple_dart_hw_reset()
479 return dart->hw->invalidate_tlb(&stream_map); in apple_dart_hw_reset()
489 stream_map.dart = domain_stream_map->dart; in apple_dart_domain_flush_tlb()
491 for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++) in apple_dart_domain_flush_tlb()
492 stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]); in apple_dart_domain_flush_tlb()
494 stream_map.dart->hw->invalidate_tlb(&stream_map); in apple_dart_domain_flush_tlb()
519 struct io_pgtable_ops *ops = dart_domain->pgtbl_ops; in apple_dart_iova_to_phys()
524 return ops->iova_to_phys(ops, iova); in apple_dart_iova_to_phys()
533 struct io_pgtable_ops *ops = dart_domain->pgtbl_ops; in apple_dart_map_pages()
536 return -ENODEV; in apple_dart_map_pages()
538 return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp, in apple_dart_map_pages()
548 struct io_pgtable_ops *ops = dart_domain->pgtbl_ops; in apple_dart_unmap_pages()
550 return ops->unmap_pages(ops, iova, pgsize, pgcount, gather); in apple_dart_unmap_pages()
559 &io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg; in apple_dart_setup_translation()
561 for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i) in apple_dart_setup_translation()
563 pgtbl_cfg->apple_dart_cfg.ttbr[i]); in apple_dart_setup_translation()
564 for (; i < stream_map->dart->hw->ttbr_count; ++i) in apple_dart_setup_translation()
568 stream_map->dart->hw->invalidate_tlb(stream_map); in apple_dart_setup_translation()
575 struct apple_dart *dart = cfg->stream_maps[0].dart; in apple_dart_finalize_domain() local
580 mutex_lock(&dart_domain->init_lock); in apple_dart_finalize_domain()
582 if (dart_domain->finalized) in apple_dart_finalize_domain()
586 dart_domain->stream_maps[i].dart = cfg->stream_maps[i].dart; in apple_dart_finalize_domain()
587 for (j = 0; j < BITS_TO_LONGS(dart->num_streams); j++) in apple_dart_finalize_domain()
588 atomic_long_set(&dart_domain->stream_maps[i].sidmap[j], in apple_dart_finalize_domain()
589 cfg->stream_maps[i].sidmap[j]); in apple_dart_finalize_domain()
593 .pgsize_bitmap = dart->pgsize, in apple_dart_finalize_domain()
594 .ias = dart->ias, in apple_dart_finalize_domain()
595 .oas = dart->oas, in apple_dart_finalize_domain()
597 .iommu_dev = dart->dev, in apple_dart_finalize_domain()
600 dart_domain->pgtbl_ops = in apple_dart_finalize_domain()
601 alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg, domain); in apple_dart_finalize_domain()
602 if (!dart_domain->pgtbl_ops) { in apple_dart_finalize_domain()
603 ret = -ENOMEM; in apple_dart_finalize_domain()
607 domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap; in apple_dart_finalize_domain()
608 domain->geometry.aperture_start = 0; in apple_dart_finalize_domain()
609 domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(dart->ias); in apple_dart_finalize_domain()
610 domain->geometry.force_aperture = true; in apple_dart_finalize_domain()
612 dart_domain->finalized = true; in apple_dart_finalize_domain()
615 mutex_unlock(&dart_domain->init_lock); in apple_dart_finalize_domain()
627 if (domain_maps[i].dart != master_maps[i].dart) in apple_dart_mod_streams()
628 return -EINVAL; in apple_dart_mod_streams()
632 if (!domain_maps[i].dart) in apple_dart_mod_streams()
634 for (j = 0; j < BITS_TO_LONGS(domain_maps[i].dart->num_streams); j++) { in apple_dart_mod_streams()
650 return apple_dart_mod_streams(domain->stream_maps, cfg->stream_maps, in apple_dart_domain_add_streams()
662 if (cfg->stream_maps[0].dart->force_bypass && in apple_dart_attach_dev()
663 domain->type != IOMMU_DOMAIN_IDENTITY) in apple_dart_attach_dev()
664 return -EINVAL; in apple_dart_attach_dev()
665 if (!cfg->stream_maps[0].dart->supports_bypass && in apple_dart_attach_dev()
666 domain->type == IOMMU_DOMAIN_IDENTITY) in apple_dart_attach_dev()
667 return -EINVAL; in apple_dart_attach_dev()
673 switch (domain->type) { in apple_dart_attach_dev()
702 return ERR_PTR(-ENODEV); in apple_dart_probe_device()
706 dev, stream_map->dart->dev, in apple_dart_probe_device()
709 return &cfg->stream_maps[0].dart->iommu; in apple_dart_probe_device()
732 mutex_init(&dart_domain->init_lock); in apple_dart_domain_alloc()
736 dart_domain->finalized = true; in apple_dart_domain_alloc()
738 return &dart_domain->domain; in apple_dart_domain_alloc()
745 if (dart_domain->pgtbl_ops) in apple_dart_domain_free()
746 free_io_pgtable_ops(dart_domain->pgtbl_ops); in apple_dart_domain_free()
754 struct platform_device *iommu_pdev = of_find_device_by_node(args->np); in apple_dart_of_xlate()
755 struct apple_dart *dart = platform_get_drvdata(iommu_pdev); in apple_dart_of_xlate() local
759 if (args->args_count != 1) in apple_dart_of_xlate()
760 return -EINVAL; in apple_dart_of_xlate()
761 sid = args->args[0]; in apple_dart_of_xlate()
766 return -ENOMEM; in apple_dart_of_xlate()
769 cfg_dart = cfg->stream_maps[0].dart; in apple_dart_of_xlate()
771 if (cfg_dart->supports_bypass != dart->supports_bypass) in apple_dart_of_xlate()
772 return -EINVAL; in apple_dart_of_xlate()
773 if (cfg_dart->force_bypass != dart->force_bypass) in apple_dart_of_xlate()
774 return -EINVAL; in apple_dart_of_xlate()
775 if (cfg_dart->pgsize != dart->pgsize) in apple_dart_of_xlate()
776 return -EINVAL; in apple_dart_of_xlate()
780 if (cfg->stream_maps[i].dart == dart) { in apple_dart_of_xlate()
781 set_bit(sid, cfg->stream_maps[i].sidmap); in apple_dart_of_xlate()
786 if (!cfg->stream_maps[i].dart) { in apple_dart_of_xlate()
787 cfg->stream_maps[i].dart = dart; in apple_dart_of_xlate()
788 set_bit(sid, cfg->stream_maps[i].sidmap); in apple_dart_of_xlate()
793 return -EINVAL; in apple_dart_of_xlate()
807 for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) in apple_dart_release_group()
808 stream_map->dart->sid2group[sid] = NULL; in apple_dart_release_group()
821 * just assume that both src and dst only have the same single DART. in apple_dart_merge_master_cfg()
823 if (src->stream_maps[1].dart) in apple_dart_merge_master_cfg()
824 return -EINVAL; in apple_dart_merge_master_cfg()
825 if (dst->stream_maps[1].dart) in apple_dart_merge_master_cfg()
826 return -EINVAL; in apple_dart_merge_master_cfg()
827 if (src->stream_maps[0].dart != dst->stream_maps[0].dart) in apple_dart_merge_master_cfg()
828 return -EINVAL; in apple_dart_merge_master_cfg()
830 bitmap_or(dst->stream_maps[0].sidmap, in apple_dart_merge_master_cfg()
831 dst->stream_maps[0].sidmap, in apple_dart_merge_master_cfg()
832 src->stream_maps[0].sidmap, in apple_dart_merge_master_cfg()
833 dst->stream_maps[0].dart->num_streams); in apple_dart_merge_master_cfg()
844 struct iommu_group *res = ERR_PTR(-EINVAL); in apple_dart_device_group()
849 for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) { in apple_dart_device_group()
851 stream_map->dart->sid2group[sid]; in apple_dart_device_group()
854 res = ERR_PTR(-EINVAL); in apple_dart_device_group()
874 res = ERR_PTR(-ENOMEM); in apple_dart_device_group()
884 dev_err(dev, "Failed to merge DART IOMMU grups.\n"); in apple_dart_device_group()
902 for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) in apple_dart_device_group()
903 stream_map->dart->sid2group[sid] = group; in apple_dart_device_group()
916 if (cfg->stream_maps[0].dart->force_bypass) in apple_dart_def_domain_type()
918 if (!cfg->stream_maps[0].dart->supports_bypass) in apple_dart_def_domain_type()
943 list_add_tail(®ion->list, head); in apple_dart_get_resv_regions()
957 .pgsize_bitmap = -1UL, /* Restricted during dart probe */
973 struct apple_dart *dart = dev; in apple_dart_t8020_irq() local
975 u32 error = readl(dart->regs + DART_T8020_ERROR); in apple_dart_t8020_irq()
977 u32 addr_lo = readl(dart->regs + DART_T8020_ERROR_ADDR_LO); in apple_dart_t8020_irq()
978 u32 addr_hi = readl(dart->regs + DART_T8020_ERROR_ADDR_HI); in apple_dart_t8020_irq()
1000 dart->dev, in apple_dart_t8020_irq()
1004 writel(error, dart->regs + DART_T8020_ERROR); in apple_dart_t8020_irq()
1010 struct apple_dart *dart = dev; in apple_dart_t8110_irq() local
1012 u32 error = readl(dart->regs + DART_T8110_ERROR); in apple_dart_t8110_irq()
1014 u32 addr_lo = readl(dart->regs + DART_T8110_ERROR_ADDR_LO); in apple_dart_t8110_irq()
1015 u32 addr_hi = readl(dart->regs + DART_T8110_ERROR_ADDR_HI); in apple_dart_t8110_irq()
1039 dart->dev, in apple_dart_t8110_irq()
1043 writel(error, dart->regs + DART_T8110_ERROR); in apple_dart_t8110_irq()
1052 struct apple_dart *dart; in apple_dart_probe() local
1053 struct device *dev = &pdev->dev; in apple_dart_probe()
1055 dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL); in apple_dart_probe()
1056 if (!dart) in apple_dart_probe()
1057 return -ENOMEM; in apple_dart_probe()
1059 dart->dev = dev; in apple_dart_probe()
1060 dart->hw = of_device_get_match_data(dev); in apple_dart_probe()
1061 spin_lock_init(&dart->lock); in apple_dart_probe()
1063 dart->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); in apple_dart_probe()
1064 if (IS_ERR(dart->regs)) in apple_dart_probe()
1065 return PTR_ERR(dart->regs); in apple_dart_probe()
1069 return -EINVAL; in apple_dart_probe()
1072 dart->irq = platform_get_irq(pdev, 0); in apple_dart_probe()
1073 if (dart->irq < 0) in apple_dart_probe()
1074 return -ENODEV; in apple_dart_probe()
1076 ret = devm_clk_bulk_get_all(dev, &dart->clks); in apple_dart_probe()
1079 dart->num_clks = ret; in apple_dart_probe()
1081 ret = clk_bulk_prepare_enable(dart->num_clks, dart->clks); in apple_dart_probe()
1085 dart_params[0] = readl(dart->regs + DART_PARAMS1); in apple_dart_probe()
1086 dart_params[1] = readl(dart->regs + DART_PARAMS2); in apple_dart_probe()
1087 dart->pgsize = 1 << FIELD_GET(DART_PARAMS1_PAGE_SHIFT, dart_params[0]); in apple_dart_probe()
1088 dart->supports_bypass = dart_params[1] & DART_PARAMS2_BYPASS_SUPPORT; in apple_dart_probe()
1090 switch (dart->hw->type) { in apple_dart_probe()
1093 dart->ias = 32; in apple_dart_probe()
1094 dart->oas = dart->hw->oas; in apple_dart_probe()
1095 dart->num_streams = dart->hw->max_sid_count; in apple_dart_probe()
1099 dart_params[2] = readl(dart->regs + DART_T8110_PARAMS3); in apple_dart_probe()
1100 dart_params[3] = readl(dart->regs + DART_T8110_PARAMS4); in apple_dart_probe()
1101 dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]); in apple_dart_probe()
1102 dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]); in apple_dart_probe()
1103 dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]); in apple_dart_probe()
1107 if (dart->num_streams > DART_MAX_STREAMS) { in apple_dart_probe()
1108 dev_err(&pdev->dev, "Too many streams (%d > %d)\n", in apple_dart_probe()
1109 dart->num_streams, DART_MAX_STREAMS); in apple_dart_probe()
1110 ret = -EINVAL; in apple_dart_probe()
1114 dart->force_bypass = dart->pgsize > PAGE_SIZE; in apple_dart_probe()
1116 ret = apple_dart_hw_reset(dart); in apple_dart_probe()
1120 ret = request_irq(dart->irq, dart->hw->irq_handler, IRQF_SHARED, in apple_dart_probe()
1121 "apple-dart fault handler", dart); in apple_dart_probe()
1125 platform_set_drvdata(pdev, dart); in apple_dart_probe()
1127 ret = iommu_device_sysfs_add(&dart->iommu, dev, NULL, "apple-dart.%s", in apple_dart_probe()
1128 dev_name(&pdev->dev)); in apple_dart_probe()
1132 ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev); in apple_dart_probe()
1137 &pdev->dev, in apple_dart_probe()
1138 "DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n", in apple_dart_probe()
1139 dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass); in apple_dart_probe()
1143 iommu_device_sysfs_remove(&dart->iommu); in apple_dart_probe()
1145 free_irq(dart->irq, dart); in apple_dart_probe()
1147 clk_bulk_disable_unprepare(dart->num_clks, dart->clks); in apple_dart_probe()
1154 struct apple_dart *dart = platform_get_drvdata(pdev); in apple_dart_remove() local
1156 apple_dart_hw_reset(dart); in apple_dart_remove()
1157 free_irq(dart->irq, dart); in apple_dart_remove()
1159 iommu_device_unregister(&dart->iommu); in apple_dart_remove()
1160 iommu_device_sysfs_remove(&dart->iommu); in apple_dart_remove()
1162 clk_bulk_disable_unprepare(dart->num_clks, dart->clks); in apple_dart_remove()
1243 struct apple_dart *dart = dev_get_drvdata(dev); in apple_dart_suspend() local
1246 for (sid = 0; sid < dart->num_streams; sid++) { in apple_dart_suspend()
1247 dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid)); in apple_dart_suspend()
1248 for (idx = 0; idx < dart->hw->ttbr_count; idx++) in apple_dart_suspend()
1249 dart->save_ttbr[sid][idx] = in apple_dart_suspend()
1250 readl(dart->regs + DART_TTBR(dart, sid, idx)); in apple_dart_suspend()
1258 struct apple_dart *dart = dev_get_drvdata(dev); in apple_dart_resume() local
1262 ret = apple_dart_hw_reset(dart); in apple_dart_resume()
1264 dev_err(dev, "Failed to reset DART on resume\n"); in apple_dart_resume()
1268 for (sid = 0; sid < dart->num_streams; sid++) { in apple_dart_resume()
1269 for (idx = 0; idx < dart->hw->ttbr_count; idx++) in apple_dart_resume()
1270 writel(dart->save_ttbr[sid][idx], in apple_dart_resume()
1271 dart->regs + DART_TTBR(dart, sid, idx)); in apple_dart_resume()
1272 writel(dart->save_tcr[sid], dart->regs + DART_TCR(dart, sid)); in apple_dart_resume()
1281 { .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 },
1282 { .compatible = "apple,t8110-dart", .data = &apple_dart_hw_t8110 },
1283 { .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 },
1290 .name = "apple-dart",
1301 MODULE_DESCRIPTION("IOMMU API for Apple's DART");