| /* SPDX-License-Identifier: GPL-2.0+ */ |
| /* |
| * Copyright (C) 2023 Loongson Technology Corporation Limited |
| */ |
| |
| #ifndef __LSDC_DRV_H__ |
| #define __LSDC_DRV_H__ |
| |
| #include <linux/pci.h> |
| |
| #include <drm/drm_connector.h> |
| #include <drm/drm_crtc.h> |
| #include <drm/drm_device.h> |
| #include <drm/drm_encoder.h> |
| #include <drm/drm_file.h> |
| #include <drm/drm_plane.h> |
| #include <drm/ttm/ttm_device.h> |
| |
| #include "lsdc_i2c.h" |
| #include "lsdc_irq.h" |
| #include "lsdc_gfxpll.h" |
| #include "lsdc_output.h" |
| #include "lsdc_pixpll.h" |
| #include "lsdc_regs.h" |
| |
| /* Currently, all Loongson display controllers have two display pipes. */ |
| #define LSDC_NUM_CRTC 2 |
| |
| /* |
| * LS7A1000/LS7A2000 chipsets function as the south & north bridges of the |
| * Loongson 3 series processors, they are equipped with on-board video RAM |
| * typically. While Loongson LS2K series are low cost SoCs which share the |
| * system RAM as video RAM, they don't has a dedicated VRAM. |
| * |
| * There is only a 1:1 mapping of crtcs, encoders and connectors for the DC |
| * |
| * display pipe 0 = crtc0 + dvo0 + encoder0 + connector0 + cursor0 + primary0 |
| * display pipe 1 = crtc1 + dvo1 + encoder1 + connectro1 + cursor1 + primary1 |
| */ |
| |
| enum loongson_chip_id { |
| CHIP_LS7A1000 = 0, |
| CHIP_LS7A2000 = 1, |
| CHIP_LS_LAST, |
| }; |
| |
| const struct lsdc_desc * |
| lsdc_device_probe(struct pci_dev *pdev, enum loongson_chip_id chip); |
| |
| struct lsdc_kms_funcs; |
| |
| /* DC specific */ |
| |
| struct lsdc_desc { |
| u32 num_of_crtc; |
| u32 max_pixel_clk; |
| u32 max_width; |
| u32 max_height; |
| u32 num_of_hw_cursor; |
| u32 hw_cursor_w; |
| u32 hw_cursor_h; |
| u32 pitch_align; /* CRTC DMA alignment constraint */ |
| bool has_vblank_counter; /* 32 bit hw vsync counter */ |
| |
| /* device dependent ops, dc side */ |
| const struct lsdc_kms_funcs *funcs; |
| }; |
| |
| /* GFX related resources wrangler */ |
| |
| struct loongson_gfx_desc { |
| struct lsdc_desc dc; |
| |
| u32 conf_reg_base; |
| |
| /* GFXPLL shared by the DC, GMC and GPU */ |
| struct { |
| u32 reg_offset; |
| u32 reg_size; |
| } gfxpll; |
| |
| /* Pixel PLL, per display pipe */ |
| struct { |
| u32 reg_offset; |
| u32 reg_size; |
| } pixpll[LSDC_NUM_CRTC]; |
| |
| enum loongson_chip_id chip_id; |
| char model[64]; |
| }; |
| |
| static inline const struct loongson_gfx_desc * |
| to_loongson_gfx(const struct lsdc_desc *dcp) |
| { |
| return container_of_const(dcp, struct loongson_gfx_desc, dc); |
| }; |
| |
| struct lsdc_reg32 { |
| char *name; |
| u32 offset; |
| }; |
| |
| /* crtc hardware related ops */ |
| |
| struct lsdc_crtc; |
| |
| struct lsdc_crtc_hw_ops { |
| void (*enable)(struct lsdc_crtc *lcrtc); |
| void (*disable)(struct lsdc_crtc *lcrtc); |
| void (*enable_vblank)(struct lsdc_crtc *lcrtc); |
| void (*disable_vblank)(struct lsdc_crtc *lcrtc); |
| void (*flip)(struct lsdc_crtc *lcrtc); |
| void (*clone)(struct lsdc_crtc *lcrtc); |
| void (*get_scan_pos)(struct lsdc_crtc *lcrtc, int *hpos, int *vpos); |
| void (*set_mode)(struct lsdc_crtc *lcrtc, const struct drm_display_mode *mode); |
| void (*soft_reset)(struct lsdc_crtc *lcrtc); |
| void (*reset)(struct lsdc_crtc *lcrtc); |
| |
| u32 (*get_vblank_counter)(struct lsdc_crtc *lcrtc); |
| void (*set_dma_step)(struct lsdc_crtc *lcrtc, enum lsdc_dma_steps step); |
| }; |
| |
| struct lsdc_crtc { |
| struct drm_crtc base; |
| struct lsdc_pixpll pixpll; |
| struct lsdc_device *ldev; |
| const struct lsdc_crtc_hw_ops *hw_ops; |
| const struct lsdc_reg32 *preg; |
| unsigned int nreg; |
| struct drm_info_list *p_info_list; |
| unsigned int n_info_list; |
| bool has_vblank; |
| }; |
| |
| /* primary plane hardware related ops */ |
| |
| struct lsdc_primary; |
| |
| struct lsdc_primary_plane_ops { |
| void (*update_fb_addr)(struct lsdc_primary *plane, u64 addr); |
| void (*update_fb_stride)(struct lsdc_primary *plane, u32 stride); |
| void (*update_fb_format)(struct lsdc_primary *plane, |
| const struct drm_format_info *format); |
| }; |
| |
| struct lsdc_primary { |
| struct drm_plane base; |
| const struct lsdc_primary_plane_ops *ops; |
| struct lsdc_device *ldev; |
| }; |
| |
| /* cursor plane hardware related ops */ |
| |
| struct lsdc_cursor; |
| |
| struct lsdc_cursor_plane_ops { |
| void (*update_bo_addr)(struct lsdc_cursor *plane, u64 addr); |
| void (*update_cfg)(struct lsdc_cursor *plane, |
| enum lsdc_cursor_size cursor_size, |
| enum lsdc_cursor_format); |
| void (*update_position)(struct lsdc_cursor *plane, int x, int y); |
| }; |
| |
| struct lsdc_cursor { |
| struct drm_plane base; |
| const struct lsdc_cursor_plane_ops *ops; |
| struct lsdc_device *ldev; |
| }; |
| |
| struct lsdc_output { |
| struct drm_encoder encoder; |
| struct drm_connector connector; |
| }; |
| |
| static inline struct lsdc_output * |
| connector_to_lsdc_output(struct drm_connector *connector) |
| { |
| return container_of(connector, struct lsdc_output, connector); |
| } |
| |
| static inline struct lsdc_output * |
| encoder_to_lsdc_output(struct drm_encoder *encoder) |
| { |
| return container_of(encoder, struct lsdc_output, encoder); |
| } |
| |
| struct lsdc_display_pipe { |
| struct lsdc_crtc crtc; |
| struct lsdc_primary primary; |
| struct lsdc_cursor cursor; |
| struct lsdc_output output; |
| struct lsdc_i2c *li2c; |
| unsigned int index; |
| }; |
| |
| static inline struct lsdc_display_pipe * |
| output_to_display_pipe(struct lsdc_output *output) |
| { |
| return container_of(output, struct lsdc_display_pipe, output); |
| } |
| |
| struct lsdc_kms_funcs { |
| irqreturn_t (*irq_handler)(int irq, void *arg); |
| |
| int (*create_i2c)(struct drm_device *ddev, |
| struct lsdc_display_pipe *dispipe, |
| unsigned int index); |
| |
| int (*output_init)(struct drm_device *ddev, |
| struct lsdc_display_pipe *dispipe, |
| struct i2c_adapter *ddc, |
| unsigned int index); |
| |
| int (*cursor_plane_init)(struct drm_device *ddev, |
| struct drm_plane *plane, |
| unsigned int index); |
| |
| int (*primary_plane_init)(struct drm_device *ddev, |
| struct drm_plane *plane, |
| unsigned int index); |
| |
| int (*crtc_init)(struct drm_device *ddev, |
| struct drm_crtc *crtc, |
| struct drm_plane *primary, |
| struct drm_plane *cursor, |
| unsigned int index, |
| bool has_vblank); |
| }; |
| |
| static inline struct lsdc_crtc * |
| to_lsdc_crtc(struct drm_crtc *crtc) |
| { |
| return container_of(crtc, struct lsdc_crtc, base); |
| } |
| |
| static inline struct lsdc_display_pipe * |
| crtc_to_display_pipe(struct drm_crtc *crtc) |
| { |
| return container_of(crtc, struct lsdc_display_pipe, crtc.base); |
| } |
| |
| static inline struct lsdc_primary * |
| to_lsdc_primary(struct drm_plane *plane) |
| { |
| return container_of(plane, struct lsdc_primary, base); |
| } |
| |
| static inline struct lsdc_cursor * |
| to_lsdc_cursor(struct drm_plane *plane) |
| { |
| return container_of(plane, struct lsdc_cursor, base); |
| } |
| |
| struct lsdc_crtc_state { |
| struct drm_crtc_state base; |
| struct lsdc_pixpll_parms pparms; |
| }; |
| |
| struct lsdc_gem { |
| /* @mutex: protect objects list */ |
| struct mutex mutex; |
| struct list_head objects; |
| }; |
| |
| struct lsdc_device { |
| struct drm_device base; |
| struct ttm_device bdev; |
| |
| /* @descp: features description of the DC variant */ |
| const struct lsdc_desc *descp; |
| struct pci_dev *dc; |
| struct pci_dev *gpu; |
| |
| struct loongson_gfxpll *gfxpll; |
| |
| /* @reglock: protects concurrent access */ |
| spinlock_t reglock; |
| |
| void __iomem *reg_base; |
| resource_size_t vram_base; |
| resource_size_t vram_size; |
| |
| resource_size_t gtt_base; |
| resource_size_t gtt_size; |
| |
| struct lsdc_display_pipe dispipe[LSDC_NUM_CRTC]; |
| |
| struct lsdc_gem gem; |
| |
| u32 irq_status; |
| |
| /* tracking pinned memory */ |
| size_t vram_pinned_size; |
| size_t gtt_pinned_size; |
| |
| /* @num_output: count the number of active display pipe */ |
| unsigned int num_output; |
| }; |
| |
| static inline struct lsdc_device *tdev_to_ldev(struct ttm_device *bdev) |
| { |
| return container_of(bdev, struct lsdc_device, bdev); |
| } |
| |
| static inline struct lsdc_device *to_lsdc(struct drm_device *ddev) |
| { |
| return container_of(ddev, struct lsdc_device, base); |
| } |
| |
| static inline struct lsdc_crtc_state * |
| to_lsdc_crtc_state(struct drm_crtc_state *base) |
| { |
| return container_of(base, struct lsdc_crtc_state, base); |
| } |
| |
| void lsdc_debugfs_init(struct drm_minor *minor); |
| |
| int ls7a1000_crtc_init(struct drm_device *ddev, |
| struct drm_crtc *crtc, |
| struct drm_plane *primary, |
| struct drm_plane *cursor, |
| unsigned int index, |
| bool no_vblank); |
| |
| int ls7a2000_crtc_init(struct drm_device *ddev, |
| struct drm_crtc *crtc, |
| struct drm_plane *primary, |
| struct drm_plane *cursor, |
| unsigned int index, |
| bool no_vblank); |
| |
| int lsdc_primary_plane_init(struct drm_device *ddev, |
| struct drm_plane *plane, |
| unsigned int index); |
| |
| int ls7a1000_cursor_plane_init(struct drm_device *ddev, |
| struct drm_plane *plane, |
| unsigned int index); |
| |
| int ls7a2000_cursor_plane_init(struct drm_device *ddev, |
| struct drm_plane *plane, |
| unsigned int index); |
| |
| /* Registers access helpers */ |
| |
| static inline u32 lsdc_rreg32(struct lsdc_device *ldev, u32 offset) |
| { |
| return readl(ldev->reg_base + offset); |
| } |
| |
| static inline void lsdc_wreg32(struct lsdc_device *ldev, u32 offset, u32 val) |
| { |
| writel(val, ldev->reg_base + offset); |
| } |
| |
| static inline void lsdc_ureg32_set(struct lsdc_device *ldev, |
| u32 offset, |
| u32 mask) |
| { |
| void __iomem *addr = ldev->reg_base + offset; |
| u32 val = readl(addr); |
| |
| writel(val | mask, addr); |
| } |
| |
| static inline void lsdc_ureg32_clr(struct lsdc_device *ldev, |
| u32 offset, |
| u32 mask) |
| { |
| void __iomem *addr = ldev->reg_base + offset; |
| u32 val = readl(addr); |
| |
| writel(val & ~mask, addr); |
| } |
| |
| static inline u32 lsdc_pipe_rreg32(struct lsdc_device *ldev, |
| u32 offset, u32 pipe) |
| { |
| return readl(ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET); |
| } |
| |
| static inline void lsdc_pipe_wreg32(struct lsdc_device *ldev, |
| u32 offset, u32 pipe, u32 val) |
| { |
| writel(val, ldev->reg_base + offset + pipe * CRTC_PIPE_OFFSET); |
| } |
| |
| #endif |