/* SPDX-License-Identifier: GPL-2.0+ */ #ifndef KPC_DMA_DRIVER_H #define KPC_DMA_DRIVER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../kpc.h" struct kp2000_device; struct kpc_dma_device { struct list_head list; struct platform_device *pldev; u32 __iomem *eng_regs; struct device *kpc_dma_dev; struct kobject kobj; char name[16]; int dir; // DMA_FROM_DEVICE || DMA_TO_DEVICE struct mutex sem; unsigned int irq; struct work_struct irq_work; atomic_t open_count; size_t accumulated_bytes; u32 accumulated_flags; // Descriptor "Pool" housekeeping u32 desc_pool_cnt; struct dma_pool *desc_pool; struct kpc_dma_descriptor *desc_pool_first; struct kpc_dma_descriptor *desc_pool_last; struct kpc_dma_descriptor *desc_next; struct kpc_dma_descriptor *desc_completed; }; struct dev_private_data { struct kpc_dma_device *ldev; u64 card_addr; u64 user_ctl; u64 user_ctl_last; u64 user_sts; }; struct kpc_dma_device *kpc_dma_lookup_device(int minor); extern const struct file_operations kpc_dma_fops; #define ENG_CAP_PRESENT 0x00000001 #define ENG_CAP_DIRECTION 0x00000002 #define ENG_CAP_TYPE_MASK 0x000000F0 #define ENG_CAP_NUMBER_MASK 0x0000FF00 #define ENG_CAP_CARD_ADDR_SIZE_MASK 0x007F0000 #define ENG_CAP_DESC_MAX_BYTE_CNT_MASK 0x3F000000 #define ENG_CAP_PERF_SCALE_MASK 0xC0000000 #define ENG_CTL_IRQ_ENABLE BIT(0) #define ENG_CTL_IRQ_ACTIVE BIT(1) #define ENG_CTL_DESC_COMPLETE BIT(2) #define ENG_CTL_DESC_ALIGN_ERR BIT(3) #define ENG_CTL_DESC_FETCH_ERR BIT(4) #define ENG_CTL_SW_ABORT_ERR BIT(5) #define ENG_CTL_DESC_CHAIN_END BIT(7) #define ENG_CTL_DMA_ENABLE BIT(8) #define ENG_CTL_DMA_RUNNING BIT(10) #define ENG_CTL_DMA_WAITING BIT(11) #define ENG_CTL_DMA_WAITING_PERSIST BIT(12) #define ENG_CTL_DMA_RESET_REQUEST BIT(14) #define ENG_CTL_DMA_RESET BIT(15) #define ENG_CTL_DESC_FETCH_ERR_CLASS_MASK 0x700000 struct aio_cb_data { struct dev_private_data *priv; struct kpc_dma_device *ldev; struct completion *cpl; unsigned char flags; struct kiocb *kcb; size_t len; unsigned int page_count; struct page **user_pages; struct sg_table sgt; int mapped_entry_count; }; #define ACD_FLAG_DONE 0 #define ACD_FLAG_ABORT 1 #define ACD_FLAG_ENG_ACCUM_ERROR 4 #define ACD_FLAG_ENG_ACCUM_SHORT 5 struct kpc_dma_descriptor { struct { volatile u32 DescByteCount :20; volatile u32 DescStatusErrorFlags :4; volatile u32 DescStatusFlags :8; }; volatile u32 DescUserControlLS; volatile u32 DescUserControlMS; volatile u32 DescCardAddrLS; struct { volatile u32 DescBufferByteCount :20; volatile u32 DescCardAddrMS :4; volatile u32 DescControlFlags :8; }; volatile u32 DescSystemAddrLS; volatile u32 DescSystemAddrMS; volatile u32 DescNextDescPtr; dma_addr_t MyDMAAddr; struct kpc_dma_descriptor *Next; struct aio_cb_data *acd; } __attribute__((packed)); // DescControlFlags: #define DMA_DESC_CTL_SOP BIT(7) #define DMA_DESC_CTL_EOP BIT(6) #define DMA_DESC_CTL_AFIFO BIT(2) #define DMA_DESC_CTL_IRQONERR BIT(1) #define DMA_DESC_CTL_IRQONDONE BIT(0) // DescStatusFlags: #define DMA_DESC_STS_SOP BIT(7) #define DMA_DESC_STS_EOP BIT(6) #define DMA_DESC_STS_ERROR BIT(4) #define DMA_DESC_STS_USMSZ BIT(3) #define DMA_DESC_STS_USLSZ BIT(2) #define DMA_DESC_STS_SHORT BIT(1) #define DMA_DESC_STS_COMPLETE BIT(0) // DescStatusErrorFlags: #define DMA_DESC_ESTS_ECRC BIT(2) #define DMA_DESC_ESTS_POISON BIT(1) #define DMA_DESC_ESTS_UNSUCCESSFUL BIT(0) #define DMA_DESC_ALIGNMENT 0x20 static inline u32 GetEngineCapabilities(struct kpc_dma_device *eng) { return readl(eng->eng_regs + 0); } static inline void WriteEngineControl(struct kpc_dma_device *eng, u32 value) { writel(value, eng->eng_regs + 1); } static inline u32 GetEngineControl(struct kpc_dma_device *eng) { return readl(eng->eng_regs + 1); } static inline void SetClearEngineControl(struct kpc_dma_device *eng, u32 set_bits, u32 clear_bits) { u32 val = GetEngineControl(eng); val |= set_bits; val &= ~clear_bits; WriteEngineControl(eng, val); } static inline void SetEngineNextPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc) { writel(desc->MyDMAAddr, eng->eng_regs + 2); } static inline void SetEngineSWPtr(struct kpc_dma_device *eng, struct kpc_dma_descriptor *desc) { writel(desc->MyDMAAddr, eng->eng_regs + 3); } static inline void ClearEngineCompletePtr(struct kpc_dma_device *eng) { writel(0, eng->eng_regs + 4); } static inline u32 GetEngineCompletePtr(struct kpc_dma_device *eng) { return readl(eng->eng_regs + 4); } static inline void lock_engine(struct kpc_dma_device *eng) { BUG_ON(eng == NULL); mutex_lock(&eng->sem); } static inline void unlock_engine(struct kpc_dma_device *eng) { BUG_ON(eng == NULL); mutex_unlock(&eng->sem); } /// Shared Functions void start_dma_engine(struct kpc_dma_device *eng); int setup_dma_engine(struct kpc_dma_device *eng, u32 desc_cnt); void stop_dma_engine(struct kpc_dma_device *eng); void destroy_dma_engine(struct kpc_dma_device *eng); void clear_desc(struct kpc_dma_descriptor *desc); int count_descriptors_available(struct kpc_dma_device *eng); void transfer_complete_cb(struct aio_cb_data *acd, size_t xfr_count, u32 flags); #endif /* KPC_DMA_DRIVER_H */