How to use clock gating in RTL?

What is the proper way to implement clock gating in RTL?

The clock gating signal should only toggle when the latch is closed, otherwise there is a chance for glitches and metastability issues. For an active high latch, the gating signal should toggle on the falling edge of the clock. Rising edge for active low latches.

Normally you would use an edge sensitive flop to hold latch_update_en to prevent noise on the gating signal.

always_ff @(negedge clk)
  latch_update_en <= next_latch_update_en;

always_comb
    gated_clk = (* clock_gating = "clk" *) clk & latch_update_en;

always_latch
    if(gated_clk)
         latch_data <= new_data;

Reminder: if you have a latch only deign: edge trigger flops are just master/slave latches

always_latch 
    if (clk)
      sync_latch_update_en <= next_latch_update_en;
always_latch 
    if (!clk)
      latch_update_en <= sync_latch_update_en;

Does the tool have hard time in synthesis if clk is directly "and"-ed in a always_comb block with another enable signal?

Most synthesis do have have issues with directly AND-ing a clocking. It is not always intuitive how the gating should be used. A synthesizer often has many AND gates in the library to choose from, each one has different slew, skew, and loading that very on input combinations. Though functionally the same, A & B will get different time results then B & A.

Instantiating an explicit cell from the synthesizer's library narrows the possibilities to know and anticipated behavior. A predefined clock gating cell also has attributes used by the synthesizer. Attributes include timing information for balancing the clock tree (buffer placement in the design for managing loads and parasitic).

Some synthesizers support setting attributes tags in RTL (ex: // synthesis attributes or (* attributes *)) instead of needing to explicitly instantiate a cell. There isn't a standard for how this is do so refer to your user manual.

What is the purpose of using custom clock gating cell?

The custom cell is a per-defined cell in the synthesis library with know timing information, load balancing, and other attributes. With this information, the synthesizer knows where and how to add or calibrate the buffer delay in the clock tree. This making sure the non-gated flop doesn't see the clock edge before gated flop.

                 _____       _____
IN -------------|D   Q|-----|D   Q|--- OUT
                |     |     |     |
       |\ |\    |     |     |     |
     +-| >| >---|>    |   +-|>    |
     | |/ |/    |_____|   | |_____|
     |  ___               |
CLK -+-|   \              |
       | &  )-------------+   BALANCED CLOCK : correct data sampled
GATE --|___/

Without the guidance, the gated flop's could get a delayed clock. The skew would cause the wrong data to get sampled.

                 _____       _____
IN -------------|D   Q|-----|D   Q|--- OUT
                |     |     |     |
                |     |     |     |
     +----------|>    |   +-|>    |
     |          |_____|   | |_____|
     |  ___               |
CLK -+-|   \    |\ |\     |
       | &  )---| >| >----+   UNBALANCED CLOCK : wrong data sampled
GATE --|___/    |/ |/